Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
0012439861
commit
be3e24ea3c
|
@ -13,6 +13,7 @@
|
||||||
.default-before_script:
|
.default-before_script:
|
||||||
before_script:
|
before_script:
|
||||||
- date
|
- date
|
||||||
|
- '[ "$FOSS_ONLY" = "1" ] && rm -rf ee/'
|
||||||
- export GOPATH=$CI_PROJECT_DIR/.go
|
- export GOPATH=$CI_PROJECT_DIR/.go
|
||||||
- mkdir -p $GOPATH
|
- mkdir -p $GOPATH
|
||||||
- source scripts/utils.sh
|
- source scripts/utils.sh
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
paths:
|
paths:
|
||||||
- vendor/ruby
|
- vendor/ruby
|
||||||
before_script:
|
before_script:
|
||||||
|
- '[ "$FOSS_ONLY" = "1" ] && rm -rf ee/'
|
||||||
- cd qa/
|
- cd qa/
|
||||||
- bundle install --clean --jobs=$(nproc) --path=vendor --retry=3 --quiet
|
- bundle install --clean --jobs=$(nproc) --path=vendor --retry=3 --quiet
|
||||||
- bundle check
|
- bundle check
|
||||||
|
|
|
@ -347,6 +347,7 @@ RSpec/HaveGitlabHttpStatus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Include:
|
Include:
|
||||||
- 'spec/support/shared_examples/**/*'
|
- 'spec/support/shared_examples/**/*'
|
||||||
|
- 'ee/spec/support/shared_examples/**/*'
|
||||||
|
|
||||||
Style/MultilineWhenThen:
|
Style/MultilineWhenThen:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
|
@ -38,12 +38,12 @@ export default {
|
||||||
<icon name="comment" />
|
<icon name="comment" />
|
||||||
</div>
|
</div>
|
||||||
<div class="timeline-content">
|
<div class="timeline-content">
|
||||||
<div v-html="timelineContent"></div>
|
<div ref="timelineContent" v-html="timelineContent"></div>
|
||||||
<div class="discussion-filter-actions mt-2">
|
<div class="discussion-filter-actions mt-2">
|
||||||
<gl-button variant="default" @click="selectFilter(0)">
|
<gl-button ref="showAllActivity" variant="default" @click="selectFilter(0)">
|
||||||
{{ __('Show all activity') }}
|
{{ __('Show all activity') }}
|
||||||
</gl-button>
|
</gl-button>
|
||||||
<gl-button variant="default" @click="selectFilter(1)">
|
<gl-button ref="showComments" variant="default" @click="selectFilter(1)">
|
||||||
{{ __('Show comments only') }}
|
{{ __('Show comments only') }}
|
||||||
</gl-button>
|
</gl-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,11 +12,23 @@ export default {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="note-attachment">
|
<div class="note-attachment">
|
||||||
<a v-if="attachment.image" :href="attachment.url" target="_blank" rel="noopener noreferrer">
|
<a
|
||||||
|
v-if="attachment.image"
|
||||||
|
ref="attachmentImage"
|
||||||
|
:href="attachment.url"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
<img :src="attachment.url" class="note-image-attach" />
|
<img :src="attachment.url" class="note-image-attach" />
|
||||||
</a>
|
</a>
|
||||||
<div class="attachment">
|
<div class="attachment">
|
||||||
<a v-if="attachment.url" :href="attachment.url" target="_blank" rel="noopener noreferrer">
|
<a
|
||||||
|
v-if="attachment.url"
|
||||||
|
ref="attachmentUrl"
|
||||||
|
:href="attachment.url"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
<i class="fa fa-paperclip" aria-hidden="true"> </i> {{ attachment.filename }}
|
<i class="fa fa-paperclip" aria-hidden="true"> </i> {{ attachment.filename }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -63,13 +63,13 @@ export default {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="note-header-info">
|
<div class="note-header-info">
|
||||||
<div v-if="includeToggle" class="discussion-actions">
|
<div v-if="includeToggle" ref="discussionActions" class="discussion-actions">
|
||||||
<button
|
<button
|
||||||
class="note-action-button discussion-toggle-button js-vue-toggle-button"
|
class="note-action-button discussion-toggle-button js-vue-toggle-button"
|
||||||
type="button"
|
type="button"
|
||||||
@click="handleToggle"
|
@click="handleToggle"
|
||||||
>
|
>
|
||||||
<i :class="toggleChevronClass" class="fa" aria-hidden="true"></i>
|
<i ref="chevronIcon" :class="toggleChevronClass" class="fa" aria-hidden="true"></i>
|
||||||
{{ __('Toggle thread') }}
|
{{ __('Toggle thread') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,10 +90,11 @@ export default {
|
||||||
<span class="note-headline-light note-headline-meta">
|
<span class="note-headline-light note-headline-meta">
|
||||||
<span class="system-note-message"> <slot></slot> </span>
|
<span class="system-note-message"> <slot></slot> </span>
|
||||||
<template v-if="createdAt">
|
<template v-if="createdAt">
|
||||||
<span class="system-note-separator">
|
<span ref="actionText" class="system-note-separator">
|
||||||
<template v-if="actionText">{{ actionText }}</template>
|
<template v-if="actionText">{{ actionText }}</template>
|
||||||
</span>
|
</span>
|
||||||
<a
|
<a
|
||||||
|
ref="noteTimestamp"
|
||||||
:href="noteTimestampLink"
|
:href="noteTimestampLink"
|
||||||
class="note-timestamp system-note-separator"
|
class="note-timestamp system-note-separator"
|
||||||
@click="updateTargetNoteHash"
|
@click="updateTargetNoteHash"
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import _ from 'underscore';
|
import _ from 'underscore';
|
||||||
|
import $ from 'jquery';
|
||||||
import { slugify } from '~/lib/utils/text_utility';
|
import { slugify } from '~/lib/utils/text_utility';
|
||||||
import { getLocationHash } from '~/lib/utils/url_utility';
|
import { getLocationHash } from '~/lib/utils/url_utility';
|
||||||
import { scrollToElement } from '~/lib/utils/common_utils';
|
import { scrollToElement } from '~/lib/utils/common_utils';
|
||||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||||
|
import '~/behaviors/markdown/render_gfm';
|
||||||
import EvidenceBlock from './evidence_block.vue';
|
import EvidenceBlock from './evidence_block.vue';
|
||||||
import ReleaseBlockAssets from './release_block_assets.vue';
|
import ReleaseBlockAssets from './release_block_assets.vue';
|
||||||
import ReleaseBlockFooter from './release_block_footer.vue';
|
import ReleaseBlockFooter from './release_block_footer.vue';
|
||||||
|
@ -65,7 +67,10 @@ export default {
|
||||||
return Boolean(this.glFeatures.releaseIssueSummary && !_.isEmpty(this.release.milestones));
|
return Boolean(this.glFeatures.releaseIssueSummary && !_.isEmpty(this.release.milestones));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.renderGFM();
|
||||||
|
|
||||||
const hash = getLocationHash();
|
const hash = getLocationHash();
|
||||||
if (hash && slugify(hash) === this.id) {
|
if (hash && slugify(hash) === this.id) {
|
||||||
this.isHighlighted = true;
|
this.isHighlighted = true;
|
||||||
|
@ -76,6 +81,11 @@ export default {
|
||||||
scrollToElement(this.$el);
|
scrollToElement(this.$el);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
renderGFM() {
|
||||||
|
$(this.$refs['gfm-content']).renderGFM();
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -91,7 +101,7 @@ export default {
|
||||||
<release-block-assets v-if="shouldRenderAssets" :assets="assets" />
|
<release-block-assets v-if="shouldRenderAssets" :assets="assets" />
|
||||||
<evidence-block v-if="hasEvidence && shouldShowEvidence" :release="release" />
|
<evidence-block v-if="hasEvidence && shouldShowEvidence" :release="release" />
|
||||||
|
|
||||||
<div class="card-text prepend-top-default">
|
<div ref="gfm-content" class="card-text prepend-top-default">
|
||||||
<div v-html="release.description_html"></div>
|
<div v-html="release.description_html"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module BlobViewers
|
||||||
|
class TypeEnum < BaseEnum
|
||||||
|
graphql_name 'BlobViewersType'
|
||||||
|
description 'Types of blob viewers'
|
||||||
|
|
||||||
|
value 'rich', value: :rich
|
||||||
|
value 'simple', value: :simple
|
||||||
|
value 'auxiliary', value: :auxiliary
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -36,10 +36,6 @@ module Types
|
||||||
description: 'File Name of the snippet',
|
description: 'File Name of the snippet',
|
||||||
null: true
|
null: true
|
||||||
|
|
||||||
field :content, GraphQL::STRING_TYPE,
|
|
||||||
description: 'Content of the snippet',
|
|
||||||
null: false
|
|
||||||
|
|
||||||
field :description, GraphQL::STRING_TYPE,
|
field :description, GraphQL::STRING_TYPE,
|
||||||
description: 'Description of the snippet',
|
description: 'Description of the snippet',
|
||||||
null: true
|
null: true
|
||||||
|
@ -64,6 +60,10 @@ module Types
|
||||||
description: 'Raw URL of the snippet',
|
description: 'Raw URL of the snippet',
|
||||||
null: false
|
null: false
|
||||||
|
|
||||||
|
field :blob, type: Types::Snippets::BlobType,
|
||||||
|
description: 'Snippet blob',
|
||||||
|
null: false
|
||||||
|
|
||||||
markdown_field :description_html, null: true, method: :description
|
markdown_field :description_html, null: true, method: :description
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module Snippets
|
||||||
|
# rubocop: disable Graphql/AuthorizeTypes
|
||||||
|
class BlobType < BaseObject
|
||||||
|
graphql_name 'SnippetBlob'
|
||||||
|
description 'Represents the snippet blob'
|
||||||
|
present_using SnippetBlobPresenter
|
||||||
|
|
||||||
|
field :highlighted_data, GraphQL::STRING_TYPE,
|
||||||
|
description: 'Blob highlighted data',
|
||||||
|
null: true
|
||||||
|
|
||||||
|
field :raw_path, GraphQL::STRING_TYPE,
|
||||||
|
description: 'Blob raw content endpoint path',
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :size, GraphQL::INT_TYPE,
|
||||||
|
description: 'Blob size',
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :binary, GraphQL::BOOLEAN_TYPE,
|
||||||
|
description: 'Shows whether the blob is binary',
|
||||||
|
method: :binary?,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :name, GraphQL::STRING_TYPE,
|
||||||
|
description: 'Blob name',
|
||||||
|
null: true
|
||||||
|
|
||||||
|
field :path, GraphQL::STRING_TYPE,
|
||||||
|
description: 'Blob path',
|
||||||
|
null: true
|
||||||
|
|
||||||
|
field :simple_viewer, type: Types::Snippets::BlobViewerType,
|
||||||
|
description: 'Blob content simple viewer',
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :rich_viewer, type: Types::Snippets::BlobViewerType,
|
||||||
|
description: 'Blob content rich viewer',
|
||||||
|
null: true
|
||||||
|
end
|
||||||
|
# rubocop: enable Graphql/AuthorizeTypes
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,41 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module Snippets
|
||||||
|
class BlobViewerType < BaseObject # rubocop:disable Graphql/AuthorizeTypes
|
||||||
|
graphql_name 'SnippetBlobViewer'
|
||||||
|
description 'Represents how the blob content should be displayed'
|
||||||
|
|
||||||
|
field :type, Types::BlobViewers::TypeEnum,
|
||||||
|
description: 'Type of blob viewer',
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :load_async, GraphQL::BOOLEAN_TYPE,
|
||||||
|
description: 'Shows whether the blob content is loaded async',
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :collapsed, GraphQL::BOOLEAN_TYPE,
|
||||||
|
description: 'Shows whether the blob should be displayed collapsed',
|
||||||
|
method: :collapsed?,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :too_large, GraphQL::BOOLEAN_TYPE,
|
||||||
|
description: 'Shows whether the blob too large to be displayed',
|
||||||
|
method: :too_large?,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :render_error, GraphQL::STRING_TYPE,
|
||||||
|
description: 'Error rendering the blob content',
|
||||||
|
null: true
|
||||||
|
|
||||||
|
field :file_type, GraphQL::STRING_TYPE,
|
||||||
|
description: 'Content file type',
|
||||||
|
method: :partial_name,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
field :loading_partial_name, GraphQL::STRING_TYPE,
|
||||||
|
description: 'Loading partial name',
|
||||||
|
null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,8 +5,6 @@
|
||||||
class Epic < ApplicationRecord
|
class Epic < ApplicationRecord
|
||||||
include IgnorableColumns
|
include IgnorableColumns
|
||||||
|
|
||||||
ignore_column :milestone_id, remove_after: '2020-02-01', remove_with: '12.8'
|
|
||||||
|
|
||||||
def self.link_reference_pattern
|
def self.link_reference_pattern
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
|
||||||
Gitlab::Highlight.highlight(
|
Gitlab::Highlight.highlight(
|
||||||
blob.path,
|
blob.path,
|
||||||
limited_blob_data(to: to),
|
limited_blob_data(to: to),
|
||||||
language: blob.language_from_gitattributes,
|
language: language,
|
||||||
plain: plain
|
plain: plain
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -37,4 +37,8 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
|
||||||
def all_lines
|
def all_lines
|
||||||
@all_lines ||= blob.data.lines
|
@all_lines ||= blob.data.lines
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def language
|
||||||
|
blob.language_from_gitattributes
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SnippetBlobPresenter < BlobPresenter
|
||||||
|
def highlighted_data
|
||||||
|
return if blob.binary?
|
||||||
|
|
||||||
|
if blob.rich_viewer&.partial_name == 'markup'
|
||||||
|
blob.rendered_markup
|
||||||
|
else
|
||||||
|
highlight
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def raw_path
|
||||||
|
if snippet.is_a?(ProjectSnippet)
|
||||||
|
raw_project_snippet_path(snippet.project, snippet)
|
||||||
|
else
|
||||||
|
raw_snippet_path(snippet)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def snippet
|
||||||
|
blob.snippet
|
||||||
|
end
|
||||||
|
|
||||||
|
def language
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
|
@ -36,10 +36,12 @@ class SubmitUsagePingService
|
||||||
private
|
private
|
||||||
|
|
||||||
def store_metrics(response)
|
def store_metrics(response)
|
||||||
return unless response['conv_index'].present?
|
metrics = response['conv_index'] || response['dev_ops_score']
|
||||||
|
|
||||||
|
return unless metrics.present?
|
||||||
|
|
||||||
DevOpsScore::Metric.create!(
|
DevOpsScore::Metric.create!(
|
||||||
response['conv_index'].slice(*METRICS)
|
metrics.slice(*METRICS)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,93 +1,93 @@
|
||||||
|
# This file is generated automatically by
|
||||||
|
# bin/rake gitlab:sidekiq:all_queues_yml:generate
|
||||||
|
#
|
||||||
|
# Do not edit it manually!
|
||||||
---
|
---
|
||||||
- auto_devops:auto_devops_disable
|
- auto_devops:auto_devops_disable
|
||||||
|
|
||||||
- auto_merge:auto_merge_process
|
- auto_merge:auto_merge_process
|
||||||
|
|
||||||
- chaos:chaos_cpu_spin
|
- chaos:chaos_cpu_spin
|
||||||
- chaos:chaos_db_spin
|
- chaos:chaos_db_spin
|
||||||
- chaos:chaos_kill
|
- chaos:chaos_kill
|
||||||
- chaos:chaos_leak_mem
|
- chaos:chaos_leak_mem
|
||||||
- chaos:chaos_sleep
|
- chaos:chaos_sleep
|
||||||
|
- container_repository:cleanup_container_repository
|
||||||
|
- container_repository:delete_container_repository
|
||||||
- cronjob:admin_email
|
- cronjob:admin_email
|
||||||
|
- cronjob:ci_archive_traces_cron
|
||||||
- cronjob:container_expiration_policy
|
- cronjob:container_expiration_policy
|
||||||
- cronjob:expire_build_artifacts
|
- cronjob:expire_build_artifacts
|
||||||
- cronjob:gitlab_usage_ping
|
- cronjob:gitlab_usage_ping
|
||||||
- cronjob:import_export_project_cleanup
|
- cronjob:import_export_project_cleanup
|
||||||
- cronjob:pages_domain_verification_cron
|
- cronjob:issue_due_scheduler
|
||||||
|
- cronjob:namespaces_prune_aggregation_schedules
|
||||||
- cronjob:pages_domain_removal_cron
|
- cronjob:pages_domain_removal_cron
|
||||||
- cronjob:pages_domain_ssl_renewal_cron
|
- cronjob:pages_domain_ssl_renewal_cron
|
||||||
|
- cronjob:pages_domain_verification_cron
|
||||||
- cronjob:personal_access_tokens_expiring
|
- cronjob:personal_access_tokens_expiring
|
||||||
- cronjob:pipeline_schedule
|
- cronjob:pipeline_schedule
|
||||||
- cronjob:prune_old_events
|
- cronjob:prune_old_events
|
||||||
|
- cronjob:prune_web_hook_logs
|
||||||
- cronjob:remove_expired_group_links
|
- cronjob:remove_expired_group_links
|
||||||
- cronjob:remove_expired_members
|
- cronjob:remove_expired_members
|
||||||
- cronjob:remove_unreferenced_lfs_objects
|
- cronjob:remove_unreferenced_lfs_objects
|
||||||
- cronjob:repository_archive_cache
|
- cronjob:repository_archive_cache
|
||||||
- cronjob:repository_check_dispatch
|
- cronjob:repository_check_dispatch
|
||||||
- cronjob:requests_profiles
|
- cronjob:requests_profiles
|
||||||
|
- cronjob:schedule_migrate_external_diffs
|
||||||
- cronjob:stuck_ci_jobs
|
- cronjob:stuck_ci_jobs
|
||||||
- cronjob:stuck_import_jobs
|
- cronjob:stuck_import_jobs
|
||||||
- cronjob:stuck_merge_jobs
|
- cronjob:stuck_merge_jobs
|
||||||
- cronjob:ci_archive_traces_cron
|
|
||||||
- cronjob:trending_projects
|
- cronjob:trending_projects
|
||||||
- cronjob:issue_due_scheduler
|
- deployment:deployments_finished
|
||||||
- cronjob:prune_web_hook_logs
|
- deployment:deployments_success
|
||||||
- cronjob:schedule_migrate_external_diffs
|
- gcp_cluster:cluster_configure
|
||||||
- cronjob:namespaces_prune_aggregation_schedules
|
|
||||||
|
|
||||||
- gcp_cluster:cluster_install_app
|
- gcp_cluster:cluster_install_app
|
||||||
- gcp_cluster:cluster_patch_app
|
- gcp_cluster:cluster_patch_app
|
||||||
- gcp_cluster:cluster_upgrade_app
|
|
||||||
- gcp_cluster:cluster_provision
|
|
||||||
- gcp_cluster:clusters_cleanup_app
|
|
||||||
- gcp_cluster:clusters_cleanup_project_namespace
|
|
||||||
- gcp_cluster:clusters_cleanup_service_account
|
|
||||||
- gcp_cluster:cluster_wait_for_app_installation
|
|
||||||
- gcp_cluster:wait_for_cluster_creation
|
|
||||||
- gcp_cluster:cluster_wait_for_ingress_ip_address
|
|
||||||
- gcp_cluster:cluster_configure
|
|
||||||
- gcp_cluster:cluster_project_configure
|
- gcp_cluster:cluster_project_configure
|
||||||
- gcp_cluster:clusters_applications_wait_for_uninstall_app
|
- gcp_cluster:cluster_provision
|
||||||
- gcp_cluster:clusters_applications_uninstall
|
- gcp_cluster:cluster_upgrade_app
|
||||||
- gcp_cluster:clusters_cleanup_app
|
- gcp_cluster:cluster_wait_for_app_installation
|
||||||
- gcp_cluster:clusters_cleanup_project_namespace
|
- gcp_cluster:cluster_wait_for_ingress_ip_address
|
||||||
- gcp_cluster:clusters_cleanup_service_account
|
|
||||||
- gcp_cluster:clusters_applications_activate_service
|
- gcp_cluster:clusters_applications_activate_service
|
||||||
- gcp_cluster:clusters_applications_deactivate_service
|
- gcp_cluster:clusters_applications_deactivate_service
|
||||||
|
- gcp_cluster:clusters_applications_uninstall
|
||||||
- github_import_advance_stage
|
- gcp_cluster:clusters_applications_wait_for_uninstall_app
|
||||||
|
- gcp_cluster:clusters_cleanup_app
|
||||||
|
- gcp_cluster:clusters_cleanup_project_namespace
|
||||||
|
- gcp_cluster:clusters_cleanup_service_account
|
||||||
|
- gcp_cluster:wait_for_cluster_creation
|
||||||
- github_importer:github_import_import_diff_note
|
- github_importer:github_import_import_diff_note
|
||||||
- github_importer:github_import_import_issue
|
- github_importer:github_import_import_issue
|
||||||
- github_importer:github_import_import_note
|
|
||||||
- github_importer:github_import_import_lfs_object
|
- github_importer:github_import_import_lfs_object
|
||||||
|
- github_importer:github_import_import_note
|
||||||
- github_importer:github_import_import_pull_request
|
- github_importer:github_import_import_pull_request
|
||||||
- github_importer:github_import_refresh_import_jid
|
- github_importer:github_import_refresh_import_jid
|
||||||
- github_importer:github_import_stage_finish_import
|
- github_importer:github_import_stage_finish_import
|
||||||
- github_importer:github_import_stage_import_base_data
|
- github_importer:github_import_stage_import_base_data
|
||||||
- github_importer:github_import_stage_import_issues_and_diff_notes
|
- github_importer:github_import_stage_import_issues_and_diff_notes
|
||||||
- github_importer:github_import_stage_import_notes
|
|
||||||
- github_importer:github_import_stage_import_lfs_objects
|
- github_importer:github_import_stage_import_lfs_objects
|
||||||
|
- github_importer:github_import_stage_import_notes
|
||||||
- github_importer:github_import_stage_import_pull_requests
|
- github_importer:github_import_stage_import_pull_requests
|
||||||
- github_importer:github_import_stage_import_repository
|
- github_importer:github_import_stage_import_repository
|
||||||
|
|
||||||
- hashed_storage:hashed_storage_migrator
|
- hashed_storage:hashed_storage_migrator
|
||||||
- hashed_storage:hashed_storage_rollbacker
|
|
||||||
- hashed_storage:hashed_storage_project_migrate
|
- hashed_storage:hashed_storage_project_migrate
|
||||||
- hashed_storage:hashed_storage_project_rollback
|
- hashed_storage:hashed_storage_project_rollback
|
||||||
|
- hashed_storage:hashed_storage_rollbacker
|
||||||
- mail_scheduler:mail_scheduler_issue_due
|
- mail_scheduler:mail_scheduler_issue_due
|
||||||
- mail_scheduler:mail_scheduler_notification_service
|
- mail_scheduler:mail_scheduler_notification_service
|
||||||
|
- notifications:new_release
|
||||||
|
- object_pool:object_pool_create
|
||||||
|
- object_pool:object_pool_destroy
|
||||||
|
- object_pool:object_pool_join
|
||||||
|
- object_pool:object_pool_schedule_join
|
||||||
- object_storage:object_storage_background_move
|
- object_storage:object_storage_background_move
|
||||||
- object_storage:object_storage_migrate_uploads
|
- object_storage:object_storage_migrate_uploads
|
||||||
|
- pipeline_background:archive_trace
|
||||||
|
- pipeline_background:ci_build_trace_chunk_flush
|
||||||
- pipeline_cache:expire_job_cache
|
- pipeline_cache:expire_job_cache
|
||||||
- pipeline_cache:expire_pipeline_cache
|
- pipeline_cache:expire_pipeline_cache
|
||||||
- pipeline_creation:create_pipeline
|
- pipeline_creation:create_pipeline
|
||||||
- pipeline_creation:run_pipeline_schedule
|
- pipeline_creation:run_pipeline_schedule
|
||||||
- pipeline_background:archive_trace
|
|
||||||
- pipeline_background:ci_build_trace_chunk_flush
|
|
||||||
- pipeline_default:build_coverage
|
- pipeline_default:build_coverage
|
||||||
- pipeline_default:build_trace_sections
|
- pipeline_default:build_trace_sections
|
||||||
- pipeline_default:pipeline_metrics
|
- pipeline_default:pipeline_metrics
|
||||||
|
@ -95,74 +95,67 @@
|
||||||
- pipeline_hooks:build_hooks
|
- pipeline_hooks:build_hooks
|
||||||
- pipeline_hooks:pipeline_hooks
|
- pipeline_hooks:pipeline_hooks
|
||||||
- pipeline_processing:build_finished
|
- pipeline_processing:build_finished
|
||||||
- pipeline_processing:ci_build_prepare
|
|
||||||
- pipeline_processing:build_queue
|
- pipeline_processing:build_queue
|
||||||
- pipeline_processing:build_success
|
- pipeline_processing:build_success
|
||||||
|
- pipeline_processing:ci_build_prepare
|
||||||
|
- pipeline_processing:ci_build_schedule
|
||||||
|
- pipeline_processing:ci_resource_groups_assign_resource_from_resource_group
|
||||||
- pipeline_processing:pipeline_process
|
- pipeline_processing:pipeline_process
|
||||||
- pipeline_processing:pipeline_success
|
- pipeline_processing:pipeline_success
|
||||||
- pipeline_processing:pipeline_update
|
- pipeline_processing:pipeline_update
|
||||||
- pipeline_processing:stage_update
|
- pipeline_processing:stage_update
|
||||||
- pipeline_processing:update_head_pipeline_for_merge_request
|
- pipeline_processing:update_head_pipeline_for_merge_request
|
||||||
- pipeline_processing:ci_build_schedule
|
|
||||||
- pipeline_processing:ci_resource_groups_assign_resource_from_resource_group
|
|
||||||
|
|
||||||
- deployment:deployments_success
|
|
||||||
- deployment:deployments_finished
|
|
||||||
|
|
||||||
- repository_check:repository_check_clear
|
|
||||||
- repository_check:repository_check_batch
|
- repository_check:repository_check_batch
|
||||||
|
- repository_check:repository_check_clear
|
||||||
- repository_check:repository_check_single_repository
|
- repository_check:repository_check_single_repository
|
||||||
|
|
||||||
- todos_destroyer:todos_destroyer_confidential_issue
|
- todos_destroyer:todos_destroyer_confidential_issue
|
||||||
- todos_destroyer:todos_destroyer_entity_leave
|
- todos_destroyer:todos_destroyer_entity_leave
|
||||||
- todos_destroyer:todos_destroyer_group_private
|
- todos_destroyer:todos_destroyer_group_private
|
||||||
- todos_destroyer:todos_destroyer_project_private
|
|
||||||
- todos_destroyer:todos_destroyer_private_features
|
- todos_destroyer:todos_destroyer_private_features
|
||||||
|
- todos_destroyer:todos_destroyer_project_private
|
||||||
- update_namespace_statistics:namespaces_schedule_aggregation
|
|
||||||
- update_namespace_statistics:namespaces_root_statistics
|
- update_namespace_statistics:namespaces_root_statistics
|
||||||
|
- update_namespace_statistics:namespaces_schedule_aggregation
|
||||||
- object_pool:object_pool_create
|
|
||||||
- object_pool:object_pool_schedule_join
|
|
||||||
- object_pool:object_pool_join
|
|
||||||
- object_pool:object_pool_destroy
|
|
||||||
|
|
||||||
- container_repository:delete_container_repository
|
|
||||||
- container_repository:cleanup_container_repository
|
|
||||||
|
|
||||||
- notifications:new_release
|
|
||||||
|
|
||||||
- default
|
|
||||||
- mailers # ActionMailer::DeliveryJob.queue_name
|
|
||||||
|
|
||||||
- authorized_projects
|
- authorized_projects
|
||||||
- background_migration
|
- background_migration
|
||||||
- chat_notification
|
- chat_notification
|
||||||
|
- create_evidence
|
||||||
- create_gpg_signature
|
- create_gpg_signature
|
||||||
|
- create_note_diff_file
|
||||||
|
- default
|
||||||
|
- delete_diff_files
|
||||||
- delete_merged_branches
|
- delete_merged_branches
|
||||||
|
- delete_stored_files
|
||||||
- delete_user
|
- delete_user
|
||||||
|
- detect_repository_languages
|
||||||
- email_receiver
|
- email_receiver
|
||||||
- emails_on_push
|
- emails_on_push
|
||||||
- error_tracking_issue_link
|
- error_tracking_issue_link
|
||||||
- expire_build_instance_artifacts
|
- expire_build_instance_artifacts
|
||||||
|
- file_hook
|
||||||
- git_garbage_collect
|
- git_garbage_collect
|
||||||
|
- github_import_advance_stage
|
||||||
- gitlab_shell
|
- gitlab_shell
|
||||||
- group_destroy
|
- group_destroy
|
||||||
|
- group_export
|
||||||
|
- import_issues_csv
|
||||||
- invalid_gpg_signature_update
|
- invalid_gpg_signature_update
|
||||||
- irker
|
- irker
|
||||||
|
- mailers
|
||||||
- merge
|
- merge
|
||||||
|
- merge_request_mergeability_check
|
||||||
- migrate_external_diffs
|
- migrate_external_diffs
|
||||||
- namespaceless_project_destroy
|
- namespaceless_project_destroy
|
||||||
- new_issue
|
- new_issue
|
||||||
- new_merge_request
|
- new_merge_request
|
||||||
- new_note
|
- new_note
|
||||||
- pages
|
- pages
|
||||||
- pages_domain_verification
|
|
||||||
- pages_domain_ssl_renewal
|
- pages_domain_ssl_renewal
|
||||||
- file_hook
|
- pages_domain_verification
|
||||||
|
- phabricator_import_import_tasks
|
||||||
- post_receive
|
- post_receive
|
||||||
- process_commit
|
- process_commit
|
||||||
- project_cache
|
- project_cache
|
||||||
|
- project_daily_statistics
|
||||||
- project_destroy
|
- project_destroy
|
||||||
- project_export
|
- project_export
|
||||||
- project_service
|
- project_service
|
||||||
|
@ -170,26 +163,16 @@
|
||||||
- reactive_caching
|
- reactive_caching
|
||||||
- rebase
|
- rebase
|
||||||
- remote_mirror_notification
|
- remote_mirror_notification
|
||||||
|
- repository_cleanup
|
||||||
- repository_fork
|
- repository_fork
|
||||||
- repository_import
|
- repository_import
|
||||||
- repository_remove_remote
|
- repository_remove_remote
|
||||||
|
- repository_update_remote_mirror
|
||||||
|
- self_monitoring_project_create
|
||||||
|
- self_monitoring_project_delete
|
||||||
- system_hook_push
|
- system_hook_push
|
||||||
- update_external_pull_requests
|
- update_external_pull_requests
|
||||||
- update_merge_requests
|
- update_merge_requests
|
||||||
- update_project_statistics
|
- update_project_statistics
|
||||||
- upload_checksum
|
- upload_checksum
|
||||||
- web_hook
|
- web_hook
|
||||||
- repository_update_remote_mirror
|
|
||||||
- create_note_diff_file
|
|
||||||
- delete_diff_files
|
|
||||||
- detect_repository_languages
|
|
||||||
- repository_cleanup
|
|
||||||
- delete_stored_files
|
|
||||||
- import_issues_csv
|
|
||||||
- project_daily_statistics
|
|
||||||
- create_evidence
|
|
||||||
- group_export
|
|
||||||
- self_monitoring_project_create
|
|
||||||
- self_monitoring_project_delete
|
|
||||||
- merge_request_mergeability_check
|
|
||||||
- phabricator_import_import_tasks
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Add blob and blob_viewer fields to graphql snippet type
|
||||||
|
merge_request: 22960
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Remove storage_version column from snippets
|
||||||
|
merge_request: 23315
|
||||||
|
author:
|
||||||
|
type: other
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Remove milestone_id from epics
|
||||||
|
merge_request: 23282
|
||||||
|
author: Lee Tickett
|
||||||
|
type: other
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Fix Markdown not rendering on releases page
|
||||||
|
merge_request: 23370
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -916,7 +916,7 @@ production: &base
|
||||||
# Gitaly settings
|
# Gitaly settings
|
||||||
gitaly:
|
gitaly:
|
||||||
# Path to the directory containing Gitaly client executables.
|
# Path to the directory containing Gitaly client executables.
|
||||||
client_path: /home/git/gitaly/bin
|
client_path: /home/git/gitaly
|
||||||
# Default Gitaly authentication token. Can be overridden per storage. Can
|
# Default Gitaly authentication token. Can be overridden per storage. Can
|
||||||
# be left blank when Gitaly is running locally on a Unix socket, which
|
# be left blank when Gitaly is running locally on a Unix socket, which
|
||||||
# is the normal way to deploy Gitaly.
|
# is the normal way to deploy Gitaly.
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
|
||||||
|
# for more information on how to write migrations for GitLab.
|
||||||
|
|
||||||
|
class RemoveStorageVersionColumnFromSnippets < ActiveRecord::Migration[5.2]
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
return unless column_exists?(:snippets, :storage_version)
|
||||||
|
|
||||||
|
remove_column :snippets, :storage_version
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
return if column_exists?(:snippets, :storage_version)
|
||||||
|
|
||||||
|
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
|
||||||
|
:snippets,
|
||||||
|
:storage_version,
|
||||||
|
:integer,
|
||||||
|
default: 2,
|
||||||
|
allow_null: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -3843,7 +3843,6 @@ ActiveRecord::Schema.define(version: 2020_01_21_132641) do
|
||||||
t.string "encrypted_secret_token_iv", limit: 255
|
t.string "encrypted_secret_token_iv", limit: 255
|
||||||
t.boolean "secret", default: false, null: false
|
t.boolean "secret", default: false, null: false
|
||||||
t.string "repository_storage", limit: 255, default: "default", null: false
|
t.string "repository_storage", limit: 255, default: "default", null: false
|
||||||
t.integer "storage_version", default: 2, null: false
|
|
||||||
t.index ["author_id"], name: "index_snippets_on_author_id"
|
t.index ["author_id"], name: "index_snippets_on_author_id"
|
||||||
t.index ["content"], name: "index_snippets_on_content_trigram", opclass: :gin_trgm_ops, using: :gin
|
t.index ["content"], name: "index_snippets_on_content_trigram", opclass: :gin_trgm_ops, using: :gin
|
||||||
t.index ["created_at"], name: "index_snippets_on_created_at"
|
t.index ["created_at"], name: "index_snippets_on_created_at"
|
||||||
|
|
|
@ -268,8 +268,9 @@ default value can be found in `/opt/gitlab/etc/gitlab-rails/env/RAILS_ENV`.
|
||||||
|
|
||||||
### Using negation
|
### Using negation
|
||||||
|
|
||||||
You're able to run all queues in `sidekiq_queues.yml` file on a single or
|
You're able to run all queues in the `all_queues.yml` file (or the equivalent EE
|
||||||
multiple processes with exceptions using the `--negate` flag.
|
file) on a single or multiple processes with exceptions using the `--negate`
|
||||||
|
flag.
|
||||||
|
|
||||||
For example, say you want to run a single process for all queues,
|
For example, say you want to run a single process for all queues,
|
||||||
except `process_commit` and `post_receive`:
|
except `process_commit` and `post_receive`:
|
||||||
|
|
|
@ -150,6 +150,15 @@ type BlobEdge {
|
||||||
node: Blob
|
node: Blob
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Types of blob viewers
|
||||||
|
"""
|
||||||
|
enum BlobViewersType {
|
||||||
|
auxiliary
|
||||||
|
rich
|
||||||
|
simple
|
||||||
|
}
|
||||||
|
|
||||||
type Commit {
|
type Commit {
|
||||||
"""
|
"""
|
||||||
Author of the commit
|
Author of the commit
|
||||||
|
@ -5934,9 +5943,9 @@ type Snippet implements Noteable {
|
||||||
author: User!
|
author: User!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Content of the snippet
|
Snippet blob
|
||||||
"""
|
"""
|
||||||
content: String!
|
blob: SnippetBlob!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Timestamp this snippet was created
|
Timestamp this snippet was created
|
||||||
|
@ -6049,6 +6058,91 @@ type Snippet implements Noteable {
|
||||||
webUrl: String!
|
webUrl: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Represents the snippet blob
|
||||||
|
"""
|
||||||
|
type SnippetBlob {
|
||||||
|
"""
|
||||||
|
Shows whether the blob is binary
|
||||||
|
"""
|
||||||
|
binary: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Blob highlighted data
|
||||||
|
"""
|
||||||
|
highlightedData: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Blob name
|
||||||
|
"""
|
||||||
|
name: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Blob path
|
||||||
|
"""
|
||||||
|
path: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Blob raw content endpoint path
|
||||||
|
"""
|
||||||
|
rawPath: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Blob content rich viewer
|
||||||
|
"""
|
||||||
|
richViewer: SnippetBlobViewer
|
||||||
|
|
||||||
|
"""
|
||||||
|
Blob content simple viewer
|
||||||
|
"""
|
||||||
|
simpleViewer: SnippetBlobViewer!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Blob size
|
||||||
|
"""
|
||||||
|
size: Int!
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Represents how the blob content should be displayed
|
||||||
|
"""
|
||||||
|
type SnippetBlobViewer {
|
||||||
|
"""
|
||||||
|
Shows whether the blob should be displayed collapsed
|
||||||
|
"""
|
||||||
|
collapsed: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Content file type
|
||||||
|
"""
|
||||||
|
fileType: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Shows whether the blob content is loaded async
|
||||||
|
"""
|
||||||
|
loadAsync: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Loading partial name
|
||||||
|
"""
|
||||||
|
loadingPartialName: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Error rendering the blob content
|
||||||
|
"""
|
||||||
|
renderError: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Shows whether the blob too large to be displayed
|
||||||
|
"""
|
||||||
|
tooLarge: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Type of blob viewer
|
||||||
|
"""
|
||||||
|
type: BlobViewersType!
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The connection type for Snippet.
|
The connection type for Snippet.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6275,8 +6275,8 @@
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "content",
|
"name": "blob",
|
||||||
"description": "Content of the snippet",
|
"description": "Snippet blob",
|
||||||
"args": [
|
"args": [
|
||||||
|
|
||||||
],
|
],
|
||||||
|
@ -6284,8 +6284,8 @@
|
||||||
"kind": "NON_NULL",
|
"kind": "NON_NULL",
|
||||||
"name": null,
|
"name": null,
|
||||||
"ofType": {
|
"ofType": {
|
||||||
"kind": "SCALAR",
|
"kind": "OBJECT",
|
||||||
"name": "String",
|
"name": "SnippetBlob",
|
||||||
"ofType": null
|
"ofType": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7004,6 +7004,311 @@
|
||||||
],
|
],
|
||||||
"possibleTypes": null
|
"possibleTypes": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "SnippetBlob",
|
||||||
|
"description": "Represents the snippet blob",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "binary",
|
||||||
|
"description": "Shows whether the blob is binary",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "Boolean",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "highlightedData",
|
||||||
|
"description": "Blob highlighted data",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"description": "Blob name",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "path",
|
||||||
|
"description": "Blob path",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rawPath",
|
||||||
|
"description": "Blob raw content endpoint path",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "richViewer",
|
||||||
|
"description": "Blob content rich viewer",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "SnippetBlobViewer",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "simpleViewer",
|
||||||
|
"description": "Blob content simple viewer",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "SnippetBlobViewer",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "size",
|
||||||
|
"description": "Blob size",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "Int",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"enumValues": null,
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "SnippetBlobViewer",
|
||||||
|
"description": "Represents how the blob content should be displayed",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "collapsed",
|
||||||
|
"description": "Shows whether the blob should be displayed collapsed",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "Boolean",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fileType",
|
||||||
|
"description": "Content file type",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loadAsync",
|
||||||
|
"description": "Shows whether the blob content is loaded async",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "Boolean",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loadingPartialName",
|
||||||
|
"description": "Loading partial name",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "renderError",
|
||||||
|
"description": "Error rendering the blob content",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tooLarge",
|
||||||
|
"description": "Shows whether the blob too large to be displayed",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "Boolean",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"description": "Type of blob viewer",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "ENUM",
|
||||||
|
"name": "BlobViewersType",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"enumValues": null,
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "ENUM",
|
||||||
|
"name": "BlobViewersType",
|
||||||
|
"description": "Types of blob viewers",
|
||||||
|
"fields": null,
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": null,
|
||||||
|
"enumValues": [
|
||||||
|
{
|
||||||
|
"name": "rich",
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "simple",
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "auxiliary",
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "ENUM",
|
"kind": "ENUM",
|
||||||
"name": "VisibilityScopesEnum",
|
"name": "VisibilityScopesEnum",
|
||||||
|
|
|
@ -926,15 +926,44 @@ Represents a snippet entry
|
||||||
| `project` | Project | The project the snippet is associated with |
|
| `project` | Project | The project the snippet is associated with |
|
||||||
| `author` | User! | The owner of the snippet |
|
| `author` | User! | The owner of the snippet |
|
||||||
| `fileName` | String | File Name of the snippet |
|
| `fileName` | String | File Name of the snippet |
|
||||||
| `content` | String! | Content of the snippet |
|
|
||||||
| `description` | String | Description of the snippet |
|
| `description` | String | Description of the snippet |
|
||||||
| `visibilityLevel` | VisibilityLevelsEnum! | Visibility Level of the snippet |
|
| `visibilityLevel` | VisibilityLevelsEnum! | Visibility Level of the snippet |
|
||||||
| `createdAt` | Time! | Timestamp this snippet was created |
|
| `createdAt` | Time! | Timestamp this snippet was created |
|
||||||
| `updatedAt` | Time! | Timestamp this snippet was updated |
|
| `updatedAt` | Time! | Timestamp this snippet was updated |
|
||||||
| `webUrl` | String! | Web URL of the snippet |
|
| `webUrl` | String! | Web URL of the snippet |
|
||||||
| `rawUrl` | String! | Raw URL of the snippet |
|
| `rawUrl` | String! | Raw URL of the snippet |
|
||||||
|
| `blob` | SnippetBlob! | Snippet blob |
|
||||||
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
|
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
|
||||||
|
|
||||||
|
## SnippetBlob
|
||||||
|
|
||||||
|
Represents the snippet blob
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | ---- | ---------- |
|
||||||
|
| `highlightedData` | String | Blob highlighted data |
|
||||||
|
| `rawPath` | String! | Blob raw content endpoint path |
|
||||||
|
| `size` | Int! | Blob size |
|
||||||
|
| `binary` | Boolean! | Shows whether the blob is binary |
|
||||||
|
| `name` | String | Blob name |
|
||||||
|
| `path` | String | Blob path |
|
||||||
|
| `simpleViewer` | SnippetBlobViewer! | Blob content simple viewer |
|
||||||
|
| `richViewer` | SnippetBlobViewer | Blob content rich viewer |
|
||||||
|
|
||||||
|
## SnippetBlobViewer
|
||||||
|
|
||||||
|
Represents how the blob content should be displayed
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | ---- | ---------- |
|
||||||
|
| `type` | BlobViewersType! | Type of blob viewer |
|
||||||
|
| `loadAsync` | Boolean! | Shows whether the blob content is loaded async |
|
||||||
|
| `collapsed` | Boolean! | Shows whether the blob should be displayed collapsed |
|
||||||
|
| `tooLarge` | Boolean! | Shows whether the blob too large to be displayed |
|
||||||
|
| `renderError` | String | Error rendering the blob content |
|
||||||
|
| `fileType` | String! | Content file type |
|
||||||
|
| `loadingPartialName` | String! | Loading partial name |
|
||||||
|
|
||||||
## SnippetPermissions
|
## SnippetPermissions
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|
|
|
@ -312,7 +312,7 @@ function createComponent(props = {}) {
|
||||||
`ApolloMutation` component exposes `mutate` method via scoped slot. If we want to test this method, we need to add it to mocks:
|
`ApolloMutation` component exposes `mutate` method via scoped slot. If we want to test this method, we need to add it to mocks:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const mutate = jest.fn(() => Promise.resolve());
|
const mutate = jest.fn().mockResolvedValue();
|
||||||
const $apollo = {
|
const $apollo = {
|
||||||
mutate,
|
mutate,
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,8 +17,11 @@ would be `process_something`. If you're not sure what queue a worker uses,
|
||||||
you can find it using `SomeWorker.queue`. There is almost never a reason to
|
you can find it using `SomeWorker.queue`. There is almost never a reason to
|
||||||
manually override the queue name using `sidekiq_options queue: :some_queue`.
|
manually override the queue name using `sidekiq_options queue: :some_queue`.
|
||||||
|
|
||||||
You must always add any new queues to `app/workers/all_queues.yml` or `ee/app/workers/all_queues.yml`
|
After adding a new queue, run `bin/rake
|
||||||
otherwise your worker will not run.
|
gitlab:sidekiq:all_queues_yml:generate` to regenerate
|
||||||
|
`app/workers/all_queues.yml` or `ee/app/workers/all_queues.yml` so that
|
||||||
|
it can be picked up by
|
||||||
|
[`sidekiq-cluster`](../administration/operations/extra_sidekiq_processes.md).
|
||||||
|
|
||||||
## Queue Namespaces
|
## Queue Namespaces
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,8 @@ variables:
|
||||||
|
|
||||||
If your project requires custom build configurations, it can be preferable to avoid
|
If your project requires custom build configurations, it can be preferable to avoid
|
||||||
compilation during your SAST execution and instead pass all job artifacts from an
|
compilation during your SAST execution and instead pass all job artifacts from an
|
||||||
earlier stage within the pipeline.
|
earlier stage within the pipeline. This is the current strategy when requiring
|
||||||
|
a `before_script` execution to prepare your scan job.
|
||||||
|
|
||||||
To pass your project's dependencies as artifacts, the dependencies must be included
|
To pass your project's dependencies as artifacts, the dependencies must be included
|
||||||
in the project's working directory and specified using the `artifacts:path` configuration.
|
in the project's working directory and specified using the `artifacts:path` configuration.
|
||||||
|
|
|
@ -178,7 +178,6 @@ excluded_attributes:
|
||||||
- :encrypted_secret_token
|
- :encrypted_secret_token
|
||||||
- :encrypted_secret_token_iv
|
- :encrypted_secret_token_iv
|
||||||
- :repository_storage
|
- :repository_storage
|
||||||
- :storage_version
|
|
||||||
merge_request_diff:
|
merge_request_diff:
|
||||||
- :external_diff
|
- :external_diff
|
||||||
- :stored_externally
|
- :stored_externally
|
||||||
|
|
|
@ -4,6 +4,22 @@ require 'yaml'
|
||||||
|
|
||||||
module Gitlab
|
module Gitlab
|
||||||
module SidekiqConfig
|
module SidekiqConfig
|
||||||
|
FOSS_QUEUE_CONFIG_PATH = 'app/workers/all_queues.yml'
|
||||||
|
EE_QUEUE_CONFIG_PATH = 'ee/app/workers/all_queues.yml'
|
||||||
|
|
||||||
|
QUEUE_CONFIG_PATHS = [
|
||||||
|
FOSS_QUEUE_CONFIG_PATH,
|
||||||
|
(EE_QUEUE_CONFIG_PATH if Gitlab.ee?)
|
||||||
|
].compact.freeze
|
||||||
|
|
||||||
|
# For queues that don't have explicit workers - default and mailers
|
||||||
|
DummyWorker = Struct.new(:queue)
|
||||||
|
|
||||||
|
DEFAULT_WORKERS = [
|
||||||
|
Gitlab::SidekiqConfig::Worker.new(DummyWorker.new('default'), ee: false),
|
||||||
|
Gitlab::SidekiqConfig::Worker.new(DummyWorker.new('mailers'), ee: false)
|
||||||
|
].freeze
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
include Gitlab::SidekiqConfig::CliMethods
|
include Gitlab::SidekiqConfig::CliMethods
|
||||||
|
|
||||||
|
@ -25,28 +41,46 @@ module Gitlab
|
||||||
|
|
||||||
def workers
|
def workers
|
||||||
@workers ||= begin
|
@workers ||= begin
|
||||||
result = find_workers(Rails.root.join('app', 'workers'))
|
result = []
|
||||||
result.concat(find_workers(Rails.root.join('ee', 'app', 'workers'))) if Gitlab.ee?
|
result.concat(DEFAULT_WORKERS)
|
||||||
|
result.concat(find_workers(Rails.root.join('app', 'workers'), ee: false))
|
||||||
|
|
||||||
|
if Gitlab.ee?
|
||||||
|
result.concat(find_workers(Rails.root.join('ee', 'app', 'workers'), ee: true))
|
||||||
|
end
|
||||||
|
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def workers_for_all_queues_yml
|
||||||
|
workers.partition(&:ee?).reverse.map(&:sort)
|
||||||
|
end
|
||||||
|
|
||||||
|
def all_queues_yml_outdated?
|
||||||
|
foss_workers, ee_workers = workers_for_all_queues_yml
|
||||||
|
|
||||||
|
return true if foss_workers != YAML.safe_load(File.read(FOSS_QUEUE_CONFIG_PATH))
|
||||||
|
|
||||||
|
Gitlab.ee? && ee_workers != YAML.safe_load(File.read(EE_QUEUE_CONFIG_PATH))
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def find_workers(root)
|
def find_workers(root, ee:)
|
||||||
concerns = root.join('concerns').to_s
|
concerns = root.join('concerns').to_s
|
||||||
|
|
||||||
workers = Dir[root.join('**', '*.rb')]
|
Dir[root.join('**', '*.rb')]
|
||||||
.reject { |path| path.start_with?(concerns) }
|
.reject { |path| path.start_with?(concerns) }
|
||||||
|
.map { |path| worker_from_path(path, root) }
|
||||||
|
.select { |worker| worker < Sidekiq::Worker }
|
||||||
|
.map { |worker| Gitlab::SidekiqConfig::Worker.new(worker, ee: ee) }
|
||||||
|
end
|
||||||
|
|
||||||
workers.map! do |path|
|
def worker_from_path(path, root)
|
||||||
ns = Pathname.new(path).relative_path_from(root).to_s.gsub('.rb', '')
|
ns = Pathname.new(path).relative_path_from(root).to_s.gsub('.rb', '')
|
||||||
|
|
||||||
ns.camelize.constantize
|
ns.camelize.constantize
|
||||||
end
|
|
||||||
|
|
||||||
# Skip things that aren't workers
|
|
||||||
workers.select { |w| w < Sidekiq::Worker }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module SidekiqConfig
|
||||||
|
class Worker
|
||||||
|
include Comparable
|
||||||
|
|
||||||
|
attr_reader :klass
|
||||||
|
delegate :feature_category_not_owned?, :get_feature_category,
|
||||||
|
:get_worker_resource_boundary, :latency_sensitive_worker?,
|
||||||
|
:queue, :worker_has_external_dependencies?,
|
||||||
|
to: :klass
|
||||||
|
|
||||||
|
def initialize(klass, ee:)
|
||||||
|
@klass = klass
|
||||||
|
@ee = ee
|
||||||
|
end
|
||||||
|
|
||||||
|
def ee?
|
||||||
|
@ee
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
to_yaml == case other
|
||||||
|
when self.class
|
||||||
|
other.to_yaml
|
||||||
|
else
|
||||||
|
other
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def <=>(other)
|
||||||
|
to_sort <=> other.to_sort
|
||||||
|
end
|
||||||
|
|
||||||
|
# Put namespaced queues first
|
||||||
|
def to_sort
|
||||||
|
[queue.include?(':') ? 0 : 1, queue]
|
||||||
|
end
|
||||||
|
|
||||||
|
# YAML representation
|
||||||
|
def encode_with(coder)
|
||||||
|
coder.represent_scalar(nil, to_yaml)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_yaml
|
||||||
|
queue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,48 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
return if Rails.env.production?
|
||||||
|
|
||||||
|
namespace :gitlab do
|
||||||
|
namespace :sidekiq do
|
||||||
|
namespace :all_queues_yml do
|
||||||
|
def write_yaml(path, object)
|
||||||
|
banner = <<~BANNER
|
||||||
|
# This file is generated automatically by
|
||||||
|
# bin/rake gitlab:sidekiq:all_queues_yml:generate
|
||||||
|
#
|
||||||
|
# Do not edit it manually!
|
||||||
|
BANNER
|
||||||
|
|
||||||
|
File.write(path, banner + YAML.dump(object))
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'GitLab | Generate all_queues.yml based on worker definitions'
|
||||||
|
task generate: :environment do
|
||||||
|
foss_workers, ee_workers = Gitlab::SidekiqConfig.workers_for_all_queues_yml
|
||||||
|
|
||||||
|
write_yaml(Gitlab::SidekiqConfig::FOSS_QUEUE_CONFIG_PATH, foss_workers)
|
||||||
|
|
||||||
|
if Gitlab.ee?
|
||||||
|
write_yaml(Gitlab::SidekiqConfig::EE_QUEUE_CONFIG_PATH, ee_workers)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'GitLab | Validate that all_queues.yml matches worker definitions'
|
||||||
|
task check: :environment do
|
||||||
|
if Gitlab::SidekiqConfig.all_queues_yml_outdated?
|
||||||
|
raise <<~MSG
|
||||||
|
Changes in worker queues found, please update the metadata by running:
|
||||||
|
|
||||||
|
bin/rake gitlab:sidekiq:all_queues_yml:generate
|
||||||
|
|
||||||
|
Then commit and push the changes from:
|
||||||
|
|
||||||
|
- #{Gitlab::SidekiqConfig::FOSS_QUEUE_CONFIG_PATH}
|
||||||
|
- #{Gitlab::SidekiqConfig::EE_QUEUE_CONFIG_PATH}
|
||||||
|
|
||||||
|
MSG
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -34,6 +34,7 @@ unless Rails.env.production?
|
||||||
scss_lint
|
scss_lint
|
||||||
gettext:lint
|
gettext:lint
|
||||||
lint:static_verification
|
lint:static_verification
|
||||||
|
gitlab:sidekiq:all_queues_yml:check
|
||||||
]
|
]
|
||||||
|
|
||||||
if Gitlab.ee?
|
if Gitlab.ee?
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
"@babel/plugin-syntax-import-meta": "^7.2.0",
|
"@babel/plugin-syntax-import-meta": "^7.2.0",
|
||||||
"@babel/preset-env": "^7.6.2",
|
"@babel/preset-env": "^7.6.2",
|
||||||
"@gitlab/svgs": "^1.89.0",
|
"@gitlab/svgs": "^1.89.0",
|
||||||
"@gitlab/ui": "8.17.0",
|
"@gitlab/ui": "^8.18.0",
|
||||||
"@gitlab/visual-review-tools": "1.5.1",
|
"@gitlab/visual-review-tools": "1.5.1",
|
||||||
"@sentry/browser": "^5.10.2",
|
"@sentry/browser": "^5.10.2",
|
||||||
"@sourcegraph/code-host-integration": "^0.0.18",
|
"@sourcegraph/code-host-integration": "^0.0.18",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :project_error_tracking_setting, class: 'ErrorTracking::ProjectErrorTrackingSetting' do
|
factory :project_error_tracking_setting, class: 'ErrorTracking::ProjectErrorTrackingSetting' do
|
||||||
project
|
project
|
||||||
api_url { 'https://gitlab.com/api/0/projects/sentry-org/sentry-project' }
|
api_url { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
|
||||||
enabled { true }
|
enabled { true }
|
||||||
token { 'access_token_123' }
|
token { 'access_token_123' }
|
||||||
project_name { 'Sentry Project' }
|
project_name { 'Sentry Project' }
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe 'View error details page', :js, :use_clean_rails_memory_store_caching, :sidekiq_inline do
|
||||||
|
include_context 'sentry error tracking context feature'
|
||||||
|
|
||||||
|
context 'with current user as project owner' do
|
||||||
|
before do
|
||||||
|
sign_in(project.owner)
|
||||||
|
|
||||||
|
visit details_project_error_tracking_index_path(project, issue_id: issue_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'error tracking show page'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with current user as project guest' do
|
||||||
|
let_it_be(:user) { create(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
project.add_guest(user)
|
||||||
|
sign_in(user)
|
||||||
|
|
||||||
|
visit details_project_error_tracking_index_path(project, issue_id: issue_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders not found' do
|
||||||
|
expect(page).to have_content('Page Not Found')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,69 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe 'View error details page', :js, :use_clean_rails_memory_store_caching, :sidekiq_inline do
|
||||||
|
include_context 'sentry error tracking context feature'
|
||||||
|
|
||||||
|
let_it_be(:issues_response_body) { fixture_file('sentry/issues_sample_response.json') }
|
||||||
|
let_it_be(:issues_response) { JSON.parse(issues_response_body) }
|
||||||
|
let(:issues_api_url) { "#{sentry_api_urls.issues_url}?limit=20&query=is:unresolved" }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:get, issues_api_url).with(
|
||||||
|
headers: { 'Authorization' => 'Bearer access_token_123' }
|
||||||
|
).to_return(status: 200, body: issues_response_body, headers: { 'Content-Type' => 'application/json' })
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with current user as project owner' do
|
||||||
|
before do
|
||||||
|
sign_in(project.owner)
|
||||||
|
|
||||||
|
visit project_error_tracking_index_path(project)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'error tracking index page'
|
||||||
|
end
|
||||||
|
|
||||||
|
# A bug caused the detail link to be broken for all users but the project owner
|
||||||
|
context 'with current user as project maintainer' do
|
||||||
|
let_it_be(:user) { create(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
project.add_maintainer(user)
|
||||||
|
sign_in(user)
|
||||||
|
|
||||||
|
visit project_error_tracking_index_path(project)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'error tracking index page'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with error tracking settings disabled' do
|
||||||
|
before do
|
||||||
|
project_error_tracking_settings.update(enabled: false)
|
||||||
|
sign_in(project.owner)
|
||||||
|
|
||||||
|
visit project_error_tracking_index_path(project)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders call to action' do
|
||||||
|
expect(page).to have_content('Enable error tracking')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with current user as project guest' do
|
||||||
|
let_it_be(:user) { create(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
project.add_guest(user)
|
||||||
|
sign_in(user)
|
||||||
|
|
||||||
|
visit project_error_tracking_index_path(project)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders not found' do
|
||||||
|
expect(page).to have_content('Page Not Found')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -38,7 +38,7 @@
|
||||||
},
|
},
|
||||||
"firstSeen": "2018-11-06T21:19:55Z",
|
"firstSeen": "2018-11-06T21:19:55Z",
|
||||||
"hasSeen": false,
|
"hasSeen": false,
|
||||||
"id": "503504",
|
"id": "11",
|
||||||
"isBookmarked": false,
|
"isBookmarked": false,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
"isSubscribed": true,
|
"isSubscribed": true,
|
||||||
|
@ -72,232 +72,64 @@
|
||||||
"shortId": "PUMP-STATION-1",
|
"shortId": "PUMP-STATION-1",
|
||||||
"stats": {
|
"stats": {
|
||||||
"24h": [
|
"24h": [
|
||||||
[
|
[1541451600.0, 557],
|
||||||
1541451600.0,
|
[1541455200.0, 473],
|
||||||
557
|
[1541458800.0, 914],
|
||||||
],
|
[1541462400.0, 991],
|
||||||
[
|
[1541466000.0, 925],
|
||||||
1541455200.0,
|
[1541469600.0, 881],
|
||||||
473
|
[1541473200.0, 182],
|
||||||
],
|
[1541476800.0, 490],
|
||||||
[
|
[1541480400.0, 820],
|
||||||
1541458800.0,
|
[1541484000.0, 322],
|
||||||
914
|
[1541487600.0, 836],
|
||||||
],
|
[1541491200.0, 565],
|
||||||
[
|
[1541494800.0, 758],
|
||||||
1541462400.0,
|
[1541498400.0, 880],
|
||||||
991
|
[1541502000.0, 677],
|
||||||
],
|
[1541505600.0, 381],
|
||||||
[
|
[1541509200.0, 814],
|
||||||
1541466000.0,
|
[1541512800.0, 329],
|
||||||
925
|
[1541516400.0, 446],
|
||||||
],
|
[1541520000.0, 731],
|
||||||
[
|
[1541523600.0, 111],
|
||||||
1541469600.0,
|
[1541527200.0, 926],
|
||||||
881
|
[1541530800.0, 772],
|
||||||
],
|
[1541534400.0, 400],
|
||||||
[
|
[1541538000.0, 943]
|
||||||
1541473200.0,
|
|
||||||
182
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541476800.0,
|
|
||||||
490
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541480400.0,
|
|
||||||
820
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541484000.0,
|
|
||||||
322
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541487600.0,
|
|
||||||
836
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541491200.0,
|
|
||||||
565
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541494800.0,
|
|
||||||
758
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541498400.0,
|
|
||||||
880
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541502000.0,
|
|
||||||
677
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541505600.0,
|
|
||||||
381
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541509200.0,
|
|
||||||
814
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541512800.0,
|
|
||||||
329
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541516400.0,
|
|
||||||
446
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541520000.0,
|
|
||||||
731
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541523600.0,
|
|
||||||
111
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541527200.0,
|
|
||||||
926
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541530800.0,
|
|
||||||
772
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541534400.0,
|
|
||||||
400
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541538000.0,
|
|
||||||
943
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
"30d": [
|
"30d": [
|
||||||
[
|
[1538870400.0, 565],
|
||||||
1538870400.0,
|
[1538956800.0, 12862],
|
||||||
565
|
[1539043200.0, 15617],
|
||||||
],
|
[1539129600.0, 10809],
|
||||||
[
|
[1539216000.0, 15065],
|
||||||
1538956800.0,
|
[1539302400.0, 12927],
|
||||||
12862
|
[1539388800.0, 12994],
|
||||||
],
|
[1539475200.0, 13139],
|
||||||
[
|
[1539561600.0, 11838],
|
||||||
1539043200.0,
|
[1539648000.0, 12088],
|
||||||
15617
|
[1539734400.0, 12338],
|
||||||
],
|
[1539820800.0, 12768],
|
||||||
[
|
[1539907200.0, 12816],
|
||||||
1539129600.0,
|
[1539993600.0, 15356],
|
||||||
10809
|
[1540080000.0, 10910],
|
||||||
],
|
[1540166400.0, 12306],
|
||||||
[
|
[1540252800.0, 12912],
|
||||||
1539216000.0,
|
[1540339200.0, 14700],
|
||||||
15065
|
[1540425600.0, 11890],
|
||||||
],
|
[1540512000.0, 11684],
|
||||||
[
|
[1540598400.0, 13510],
|
||||||
1539302400.0,
|
[1540684800.0, 12625],
|
||||||
12927
|
[1540771200.0, 12811],
|
||||||
],
|
[1540857600.0, 13180],
|
||||||
[
|
[1540944000.0, 14651],
|
||||||
1539388800.0,
|
[1541030400.0, 14161],
|
||||||
12994
|
[1541116800.0, 12612],
|
||||||
],
|
[1541203200.0, 14316],
|
||||||
[
|
[1541289600.0, 14742],
|
||||||
1539475200.0,
|
[1541376000.0, 12505],
|
||||||
13139
|
[1541462400.0, 14180]
|
||||||
],
|
|
||||||
[
|
|
||||||
1539561600.0,
|
|
||||||
11838
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1539648000.0,
|
|
||||||
12088
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1539734400.0,
|
|
||||||
12338
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1539820800.0,
|
|
||||||
12768
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1539907200.0,
|
|
||||||
12816
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1539993600.0,
|
|
||||||
15356
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540080000.0,
|
|
||||||
10910
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540166400.0,
|
|
||||||
12306
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540252800.0,
|
|
||||||
12912
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540339200.0,
|
|
||||||
14700
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540425600.0,
|
|
||||||
11890
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540512000.0,
|
|
||||||
11684
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540598400.0,
|
|
||||||
13510
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540684800.0,
|
|
||||||
12625
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540771200.0,
|
|
||||||
12811
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540857600.0,
|
|
||||||
13180
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1540944000.0,
|
|
||||||
14651
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541030400.0,
|
|
||||||
14161
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541116800.0,
|
|
||||||
12612
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541203200.0,
|
|
||||||
14316
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541289600.0,
|
|
||||||
14742
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541376000.0,
|
|
||||||
12505
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1541462400.0,
|
|
||||||
14180
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"status": "unresolved",
|
"status": "unresolved",
|
||||||
|
|
|
@ -18,6 +18,8 @@ exports[`grafana integration component default state to match the default snapsh
|
||||||
|
|
||||||
<gl-button-stub
|
<gl-button-stub
|
||||||
class="js-settings-toggle"
|
class="js-settings-toggle"
|
||||||
|
size="md"
|
||||||
|
variant="secondary"
|
||||||
>
|
>
|
||||||
Expand
|
Expand
|
||||||
</gl-button-stub>
|
</gl-button-stub>
|
||||||
|
@ -89,6 +91,7 @@ exports[`grafana integration component default state to match the default snapsh
|
||||||
</gl-form-group-stub>
|
</gl-form-group-stub>
|
||||||
|
|
||||||
<gl-button-stub
|
<gl-button-stub
|
||||||
|
size="md"
|
||||||
variant="success"
|
variant="success"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ describe('DateTimePicker', () => {
|
||||||
|
|
||||||
const dropdownToggle = () => dateTimePicker.find('.dropdown-toggle');
|
const dropdownToggle = () => dateTimePicker.find('.dropdown-toggle');
|
||||||
const dropdownMenu = () => dateTimePicker.find('.dropdown-menu');
|
const dropdownMenu = () => dateTimePicker.find('.dropdown-menu');
|
||||||
const applyButtonElement = () => dateTimePicker.find('button[variant="success"]').element;
|
const applyButtonElement = () => dateTimePicker.find('button.btn-success').element;
|
||||||
const cancelButtonElement = () => dateTimePicker.find('button.btn-secondary').element;
|
const cancelButtonElement = () => dateTimePicker.find('button.btn-secondary').element;
|
||||||
const fillInputAndBlur = (input, val) => {
|
const fillInputAndBlur = (input, val) => {
|
||||||
dateTimePicker.find(input).setValue(val);
|
dateTimePicker.find(input).setValue(val);
|
||||||
|
|
|
@ -1,93 +1,40 @@
|
||||||
import Vue from 'vue';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import DiscussionFilterNote from '~/notes/components/discussion_filter_note.vue';
|
import DiscussionFilterNote from '~/notes/components/discussion_filter_note.vue';
|
||||||
import eventHub from '~/notes/event_hub';
|
import eventHub from '~/notes/event_hub';
|
||||||
|
|
||||||
import mountComponent from '../../helpers/vue_mount_component_helper';
|
|
||||||
|
|
||||||
describe('DiscussionFilterNote component', () => {
|
describe('DiscussionFilterNote component', () => {
|
||||||
let vm;
|
let wrapper;
|
||||||
|
|
||||||
const createComponent = () => {
|
const createComponent = () => {
|
||||||
const Component = Vue.extend(DiscussionFilterNote);
|
wrapper = shallowMount(DiscussionFilterNote);
|
||||||
|
|
||||||
return mountComponent(Component);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vm = createComponent();
|
createComponent();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vm.$destroy();
|
wrapper.destroy();
|
||||||
|
wrapper = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('computed', () => {
|
it('timelineContent renders a string containing instruction for switching feed type', () => {
|
||||||
describe('timelineContent', () => {
|
expect(wrapper.find({ ref: 'timelineContent' }).html()).toBe(
|
||||||
it('returns string containing instruction for switching feed type', () => {
|
"<div>You're only seeing <b>other activity</b> in the feed. To add a comment, switch to one of the following options.</div>",
|
||||||
expect(vm.timelineContent).toBe(
|
);
|
||||||
"You're only seeing <b>other activity</b> in the feed. To add a comment, switch to one of the following options.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('methods', () => {
|
it('emits `dropdownSelect` event with 0 parameter on clicking Show all activity button', () => {
|
||||||
describe('selectFilter', () => {
|
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||||
it('emits `dropdownSelect` event on `eventHub` with provided param', () => {
|
wrapper.find({ ref: 'showAllActivity' }).vm.$emit('click');
|
||||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
|
||||||
|
|
||||||
vm.selectFilter(1);
|
expect(eventHub.$emit).toHaveBeenCalledWith('dropdownSelect', 0);
|
||||||
|
|
||||||
expect(eventHub.$emit).toHaveBeenCalledWith('dropdownSelect', 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('template', () => {
|
it('emits `dropdownSelect` event with 1 parameter on clicking Show comments only button', () => {
|
||||||
it('renders component container element', () => {
|
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||||
expect(vm.$el.classList.contains('discussion-filter-note')).toBe(true);
|
wrapper.find({ ref: 'showComments' }).vm.$emit('click');
|
||||||
});
|
|
||||||
|
|
||||||
it('renders comment icon element', () => {
|
expect(eventHub.$emit).toHaveBeenCalledWith('dropdownSelect', 1);
|
||||||
expect(vm.$el.querySelector('.timeline-icon svg use').getAttribute('xlink:href')).toContain(
|
|
||||||
'comment',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders filter information note', () => {
|
|
||||||
expect(vm.$el.querySelector('.timeline-content').innerText.trim()).toContain(
|
|
||||||
"You're only seeing other activity in the feed. To add a comment, switch to one of the following options.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders filter buttons', () => {
|
|
||||||
const buttonsContainerEl = vm.$el.querySelector('.discussion-filter-actions');
|
|
||||||
|
|
||||||
expect(buttonsContainerEl.querySelector('button:first-child').innerText.trim()).toContain(
|
|
||||||
'Show all activity',
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(buttonsContainerEl.querySelector('button:last-child').innerText.trim()).toContain(
|
|
||||||
'Show comments only',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('clicking `Show all activity` button calls `selectFilter("all")` method', () => {
|
|
||||||
const showAllBtn = vm.$el.querySelector('.discussion-filter-actions button:first-child');
|
|
||||||
jest.spyOn(vm, 'selectFilter').mockImplementation(() => {});
|
|
||||||
|
|
||||||
showAllBtn.dispatchEvent(new Event('click'));
|
|
||||||
|
|
||||||
expect(vm.selectFilter).toHaveBeenCalledWith(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('clicking `Show comments only` button calls `selectFilter("comments")` method', () => {
|
|
||||||
const showAllBtn = vm.$el.querySelector('.discussion-filter-actions button:last-child');
|
|
||||||
jest.spyOn(vm, 'selectFilter').mockImplementation(() => {});
|
|
||||||
|
|
||||||
showAllBtn.dispatchEvent(new Event('click'));
|
|
||||||
|
|
||||||
expect(vm.selectFilter).toHaveBeenCalledWith(1);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,23 +1,45 @@
|
||||||
import Vue from 'vue';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import noteAttachment from '~/notes/components/note_attachment.vue';
|
import NoteAttachment from '~/notes/components/note_attachment.vue';
|
||||||
|
|
||||||
describe('issue note attachment', () => {
|
describe('Issue note attachment', () => {
|
||||||
it('should render properly', () => {
|
let wrapper;
|
||||||
const props = {
|
|
||||||
attachment: {
|
const findImage = () => wrapper.find({ ref: 'attachmentImage' });
|
||||||
filename: 'dk.png',
|
const findUrl = () => wrapper.find({ ref: 'attachmentUrl' });
|
||||||
image: true,
|
|
||||||
url: '/dk.png',
|
const createComponent = attachment => {
|
||||||
|
wrapper = shallowMount(NoteAttachment, {
|
||||||
|
propsData: {
|
||||||
|
attachment,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const Component = Vue.extend(noteAttachment);
|
afterEach(() => {
|
||||||
const vm = new Component({
|
wrapper.destroy();
|
||||||
propsData: props,
|
wrapper = null;
|
||||||
}).$mount();
|
});
|
||||||
|
|
||||||
expect(vm.$el.classList.contains('note-attachment')).toBeTruthy();
|
it('renders attachment image if it is passed in attachment prop', () => {
|
||||||
expect(vm.$el.querySelector('img').src).toContain(props.attachment.url);
|
createComponent({
|
||||||
expect(vm.$el.querySelector('a').href).toContain(props.attachment.url);
|
image: 'test-image',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(findImage().exists()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders attachment url if it is passed in attachment prop', () => {
|
||||||
|
createComponent({
|
||||||
|
url: 'test-url',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(findUrl().exists()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render image and url if attachment object is empty', () => {
|
||||||
|
createComponent({});
|
||||||
|
|
||||||
|
expect(findImage().exists()).toBe(false);
|
||||||
|
expect(findUrl().exists()).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,125 +1,141 @@
|
||||||
import Vue from 'vue';
|
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||||
import noteHeader from '~/notes/components/note_header.vue';
|
import Vuex from 'vuex';
|
||||||
import createStore from '~/notes/stores';
|
import NoteHeader from '~/notes/components/note_header.vue';
|
||||||
|
|
||||||
describe('note_header component', () => {
|
const localVue = createLocalVue();
|
||||||
let store;
|
localVue.use(Vuex);
|
||||||
let vm;
|
|
||||||
let Component;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
const actions = {
|
||||||
Component = Vue.extend(noteHeader);
|
setTargetNoteHash: jest.fn(),
|
||||||
store = createStore();
|
};
|
||||||
});
|
|
||||||
|
describe('NoteHeader component', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
const findActionsWrapper = () => wrapper.find({ ref: 'discussionActions' });
|
||||||
|
const findChevronIcon = () => wrapper.find({ ref: 'chevronIcon' });
|
||||||
|
const findActionText = () => wrapper.find({ ref: 'actionText' });
|
||||||
|
const findTimestamp = () => wrapper.find({ ref: 'noteTimestamp' });
|
||||||
|
|
||||||
|
const createComponent = props => {
|
||||||
|
wrapper = shallowMount(NoteHeader, {
|
||||||
|
localVue,
|
||||||
|
store: new Vuex.Store({
|
||||||
|
actions,
|
||||||
|
}),
|
||||||
|
propsData: {
|
||||||
|
...props,
|
||||||
|
actionTextHtml: '',
|
||||||
|
noteId: '1394',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vm.$destroy();
|
wrapper.destroy();
|
||||||
|
wrapper = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('individual note', () => {
|
it('does not render discussion actions when includeToggle is false', () => {
|
||||||
beforeEach(() => {
|
createComponent({
|
||||||
vm = new Component({
|
includeToggle: false,
|
||||||
store,
|
|
||||||
propsData: {
|
|
||||||
actionText: 'commented',
|
|
||||||
actionTextHtml: '',
|
|
||||||
author: {
|
|
||||||
avatar_url: null,
|
|
||||||
id: 1,
|
|
||||||
name: 'Root',
|
|
||||||
path: '/root',
|
|
||||||
state: 'active',
|
|
||||||
username: 'root',
|
|
||||||
},
|
|
||||||
createdAt: '2017-08-02T10:51:58.559Z',
|
|
||||||
includeToggle: false,
|
|
||||||
noteId: '1394',
|
|
||||||
expanded: true,
|
|
||||||
},
|
|
||||||
}).$mount();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render user information', () => {
|
expect(findActionsWrapper().exists()).toBe(false);
|
||||||
expect(vm.$el.querySelector('.note-header-author-name').textContent.trim()).toEqual('Root');
|
});
|
||||||
expect(vm.$el.querySelector('.note-header-info a').getAttribute('href')).toEqual('/root');
|
|
||||||
expect(vm.$el.querySelector('.note-header-info a').dataset.userId).toEqual('1');
|
describe('when includes a toggle', () => {
|
||||||
expect(vm.$el.querySelector('.note-header-info a').dataset.username).toEqual('root');
|
it('renders discussion actions', () => {
|
||||||
expect(vm.$el.querySelector('.note-header-info a').classList).toContain('js-user-link');
|
createComponent({
|
||||||
|
includeToggle: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(findActionsWrapper().exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render timestamp link', () => {
|
it('emits toggleHandler event on button click', () => {
|
||||||
expect(vm.$el.querySelector('a[href="#note_1394"]')).toBeDefined();
|
createComponent({
|
||||||
|
includeToggle: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.find('.note-action-button').trigger('click');
|
||||||
|
expect(wrapper.emitted('toggleHandler')).toBeDefined();
|
||||||
|
expect(wrapper.emitted('toggleHandler')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not render user information when prop `author` is empty object', done => {
|
it('has chevron-up icon if expanded prop is true', () => {
|
||||||
vm.author = {};
|
createComponent({
|
||||||
Vue.nextTick()
|
includeToggle: true,
|
||||||
.then(() => {
|
expanded: true,
|
||||||
expect(vm.$el.querySelector('.note-header-author-name')).toBeNull();
|
});
|
||||||
})
|
|
||||||
.then(done)
|
expect(findChevronIcon().classes()).toContain('fa-chevron-up');
|
||||||
.catch(done.fail);
|
});
|
||||||
|
|
||||||
|
it('has chevron-down icon if expanded prop is false', () => {
|
||||||
|
createComponent({
|
||||||
|
includeToggle: true,
|
||||||
|
expanded: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(findChevronIcon().classes()).toContain('fa-chevron-down');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('discussion', () => {
|
it('renders an author link if author is passed to props', () => {
|
||||||
beforeEach(() => {
|
createComponent({
|
||||||
vm = new Component({
|
author: {
|
||||||
store,
|
avatar_url: null,
|
||||||
propsData: {
|
id: 1,
|
||||||
actionText: 'started a discussion',
|
name: 'Root',
|
||||||
actionTextHtml: '',
|
path: '/root',
|
||||||
author: {
|
state: 'active',
|
||||||
avatar_url: null,
|
username: 'root',
|
||||||
id: 1,
|
},
|
||||||
name: 'Root',
|
|
||||||
path: '/root',
|
|
||||||
state: 'active',
|
|
||||||
username: 'root',
|
|
||||||
},
|
|
||||||
createdAt: '2017-08-02T10:51:58.559Z',
|
|
||||||
includeToggle: true,
|
|
||||||
noteId: '1395',
|
|
||||||
expanded: true,
|
|
||||||
},
|
|
||||||
}).$mount();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render toggle button', () => {
|
expect(wrapper.find('.js-user-link').exists()).toBe(true);
|
||||||
expect(vm.$el.querySelector('.js-vue-toggle-button')).toBeDefined();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('emits toggle event on click', done => {
|
it('renders deleted user text if author is not passed as a prop', () => {
|
||||||
jest.spyOn(vm, '$emit').mockImplementation(() => {});
|
createComponent();
|
||||||
|
|
||||||
vm.$el.querySelector('.js-vue-toggle-button').click();
|
expect(wrapper.text()).toContain('A deleted user');
|
||||||
|
});
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
it('does not render created at information if createdAt is not passed as a prop', () => {
|
||||||
expect(vm.$emit).toHaveBeenCalledWith('toggleHandler');
|
createComponent();
|
||||||
done();
|
|
||||||
|
expect(findActionText().exists()).toBe(false);
|
||||||
|
expect(findTimestamp().exists()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when createdAt is passed as a prop', () => {
|
||||||
|
it('renders action text and a timestamp', () => {
|
||||||
|
createComponent({
|
||||||
|
createdAt: '2017-08-02T10:51:58.559Z',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(findActionText().exists()).toBe(true);
|
||||||
|
expect(findTimestamp().exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders up arrow when open', done => {
|
it('renders correct actionText if passed', () => {
|
||||||
vm.expanded = true;
|
createComponent({
|
||||||
|
createdAt: '2017-08-02T10:51:58.559Z',
|
||||||
Vue.nextTick(() => {
|
actionText: 'Test action text',
|
||||||
expect(vm.$el.querySelector('.js-vue-toggle-button i').classList).toContain(
|
|
||||||
'fa-chevron-up',
|
|
||||||
);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(findActionText().text()).toBe('Test action text');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders down arrow when closed', done => {
|
it('calls an action when timestamp is clicked', () => {
|
||||||
vm.expanded = false;
|
createComponent({
|
||||||
|
createdAt: '2017-08-02T10:51:58.559Z',
|
||||||
Vue.nextTick(() => {
|
|
||||||
expect(vm.$el.querySelector('.js-vue-toggle-button i').classList).toContain(
|
|
||||||
'fa-chevron-down',
|
|
||||||
);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
findTimestamp().trigger('click');
|
||||||
|
|
||||||
|
expect(actions.setTargetNoteHash).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,6 +39,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<gl-button-stub
|
<gl-button-stub
|
||||||
|
size="md"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
|
@ -46,6 +47,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
|
||||||
|
|
||||||
<gl-button-stub
|
<gl-button-stub
|
||||||
disabled="true"
|
disabled="true"
|
||||||
|
size="md"
|
||||||
variant="warning"
|
variant="warning"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
|
||||||
|
|
||||||
<gl-button-stub
|
<gl-button-stub
|
||||||
disabled="true"
|
disabled="true"
|
||||||
|
size="md"
|
||||||
variant="danger"
|
variant="danger"
|
||||||
>
|
>
|
||||||
action
|
action
|
||||||
|
|
|
@ -84,7 +84,7 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
|
||||||
class="input-group-append"
|
class="input-group-append"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn input-group-text btn-secondary btn-default"
|
class="btn input-group-text btn-secondary btn-md btn-default"
|
||||||
data-clipboard-text="docker login host"
|
data-clipboard-text="docker login host"
|
||||||
title="Copy login command"
|
title="Copy login command"
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -122,7 +122,7 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
|
||||||
class="input-group-append"
|
class="input-group-append"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn input-group-text btn-secondary btn-default"
|
class="btn input-group-text btn-secondary btn-md btn-default"
|
||||||
data-clipboard-text="docker build -t url ."
|
data-clipboard-text="docker build -t url ."
|
||||||
title="Copy build command"
|
title="Copy build command"
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -152,7 +152,7 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
|
||||||
class="input-group-append"
|
class="input-group-append"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn input-group-text btn-secondary btn-default"
|
class="btn input-group-text btn-secondary btn-md btn-default"
|
||||||
data-clipboard-text="docker push url"
|
data-clipboard-text="docker push url"
|
||||||
title="Copy push command"
|
title="Copy push command"
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
@ -159,7 +159,9 @@ exports[`Settings Form renders 1`] = `
|
||||||
>
|
>
|
||||||
<glbutton-stub
|
<glbutton-stub
|
||||||
class="mr-2 d-block"
|
class="mr-2 d-block"
|
||||||
|
size="md"
|
||||||
type="reset"
|
type="reset"
|
||||||
|
variant="secondary"
|
||||||
>
|
>
|
||||||
|
|
||||||
Cancel
|
Cancel
|
||||||
|
@ -168,6 +170,7 @@ exports[`Settings Form renders 1`] = `
|
||||||
|
|
||||||
<glbutton-stub
|
<glbutton-stub
|
||||||
class="d-flex justify-content-center align-items-center js-no-auto-disable"
|
class="d-flex justify-content-center align-items-center js-no-auto-disable"
|
||||||
|
size="md"
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="success"
|
variant="success"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import $ from 'jquery';
|
||||||
import { mount } from '@vue/test-utils';
|
import { mount } from '@vue/test-utils';
|
||||||
import { first } from 'underscore';
|
import { first } from 'underscore';
|
||||||
import EvidenceBlock from '~/releases/list/components/evidence_block.vue';
|
import EvidenceBlock from '~/releases/list/components/evidence_block.vue';
|
||||||
|
@ -43,6 +44,7 @@ describe('Release block', () => {
|
||||||
const editButton = () => wrapper.find('.js-edit-button');
|
const editButton = () => wrapper.find('.js-edit-button');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.spyOn($.fn, 'renderGFM');
|
||||||
releaseClone = JSON.parse(JSON.stringify(release));
|
releaseClone = JSON.parse(JSON.stringify(release));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -66,6 +68,11 @@ describe('Release block', () => {
|
||||||
expect(wrapper.text()).toContain(release.name);
|
expect(wrapper.text()).toContain(release.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders release description', () => {
|
||||||
|
expect(wrapper.vm.$refs['gfm-content']).toBeDefined();
|
||||||
|
expect($.fn.renderGFM).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('renders release date', () => {
|
it('renders release date', () => {
|
||||||
expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.released_at));
|
expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.released_at));
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,8 @@ exports[`self monitor component When the self monitor project has not been creat
|
||||||
|
|
||||||
<gl-button-stub
|
<gl-button-stub
|
||||||
class="js-settings-toggle"
|
class="js-settings-toggle"
|
||||||
|
size="md"
|
||||||
|
variant="secondary"
|
||||||
>
|
>
|
||||||
Expand
|
Expand
|
||||||
</gl-button-stub>
|
</gl-button-stub>
|
||||||
|
|
|
@ -1,14 +1,88 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Expand button on click when short text is provided renders button after text 1`] = `
|
exports[`Expand button on click when short text is provided renders button after text 1`] = `
|
||||||
"<span><button aria-label=\\"Click to expand text\\" type=\\"button\\" class=\\"btn js-text-expander-prepend text-expander btn-blank btn-secondary\\" style=\\"display: none;\\"><svg aria-hidden=\\"true\\" class=\\"s12 ic-ellipsis_h\\"><use xlink:href=\\"#ellipsis_h\\"></use></svg></button> <!----> <span><p>Expanded!</p></span> <button aria-label=\\"Click to expand text\\" type=\\"button\\" class=\\"btn js-text-expander-append text-expander btn-blank btn-secondary\\" style=\\"\\"><svg aria-hidden=\\"true\\" class=\\"s12 ic-ellipsis_h\\">
|
<span>
|
||||||
<use xlink:href=\\"#ellipsis_h\\"></use>
|
<button
|
||||||
</svg></button></span>"
|
aria-label="Click to expand text"
|
||||||
|
class="btn js-text-expander-prepend text-expander btn-blank btn-secondary btn-md"
|
||||||
|
style="display: none;"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="s12 ic-ellipsis_h"
|
||||||
|
>
|
||||||
|
<use
|
||||||
|
xlink:href="#ellipsis_h"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<p>
|
||||||
|
Expanded!
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<button
|
||||||
|
aria-label="Click to expand text"
|
||||||
|
class="btn js-text-expander-append text-expander btn-blank btn-secondary btn-md"
|
||||||
|
style=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="s12 ic-ellipsis_h"
|
||||||
|
>
|
||||||
|
<use
|
||||||
|
xlink:href="#ellipsis_h"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Expand button when short text is provided renders button before text 1`] = `
|
exports[`Expand button when short text is provided renders button before text 1`] = `
|
||||||
"<span><button aria-label=\\"Click to expand text\\" type=\\"button\\" class=\\"btn js-text-expander-prepend text-expander btn-blank btn-secondary\\"><svg aria-hidden=\\"true\\" class=\\"s12 ic-ellipsis_h\\"><use xlink:href=\\"#ellipsis_h\\"></use></svg></button> <span><p>Short</p></span>
|
<span>
|
||||||
<!----> <button aria-label=\\"Click to expand text\\" type=\\"button\\" class=\\"btn js-text-expander-append text-expander btn-blank btn-secondary\\" style=\\"display: none;\\"><svg aria-hidden=\\"true\\" class=\\"s12 ic-ellipsis_h\\">
|
<button
|
||||||
<use xlink:href=\\"#ellipsis_h\\"></use>
|
aria-label="Click to expand text"
|
||||||
</svg></button></span>"
|
class="btn js-text-expander-prepend text-expander btn-blank btn-secondary btn-md"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="s12 ic-ellipsis_h"
|
||||||
|
>
|
||||||
|
<use
|
||||||
|
xlink:href="#ellipsis_h"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<p>
|
||||||
|
Short
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
<button
|
||||||
|
aria-label="Click to expand text"
|
||||||
|
class="btn js-text-expander-append text-expander btn-blank btn-secondary btn-md"
|
||||||
|
style="display: none;"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="s12 ic-ellipsis_h"
|
||||||
|
>
|
||||||
|
<use
|
||||||
|
xlink:href="#ellipsis_h"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -71,7 +71,7 @@ describe('Expand button', () => {
|
||||||
it('renders button before text', () => {
|
it('renders button before text', () => {
|
||||||
expect(expanderPrependEl().isVisible()).toBe(true);
|
expect(expanderPrependEl().isVisible()).toBe(true);
|
||||||
expect(expanderAppendEl().isVisible()).toBe(false);
|
expect(expanderAppendEl().isVisible()).toBe(false);
|
||||||
expect(wrapper.find(ExpandButton).html()).toMatchSnapshot();
|
expect(wrapper.find(ExpandButton).element).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ describe('Expand button', () => {
|
||||||
it('renders button after text', () => {
|
it('renders button after text', () => {
|
||||||
expect(expanderPrependEl().isVisible()).toBe(false);
|
expect(expanderPrependEl().isVisible()).toBe(false);
|
||||||
expect(expanderAppendEl().isVisible()).toBe(true);
|
expect(expanderAppendEl().isVisible()).toBe(true);
|
||||||
expect(wrapper.find(ExpandButton).html()).toMatchSnapshot();
|
expect(wrapper.find(ExpandButton).element).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Types::BlobViewers::TypeEnum do
|
||||||
|
it { expect(described_class.graphql_name).to eq('BlobViewersType') }
|
||||||
|
|
||||||
|
it 'exposes all tree entry types' do
|
||||||
|
expect(described_class.values.keys).to include(*%w[rich simple auxiliary])
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,10 +5,10 @@ require 'spec_helper'
|
||||||
describe GitlabSchema.types['Snippet'] do
|
describe GitlabSchema.types['Snippet'] do
|
||||||
it 'has the correct fields' do
|
it 'has the correct fields' do
|
||||||
expected_fields = [:id, :title, :project, :author,
|
expected_fields = [:id, :title, :project, :author,
|
||||||
:file_name, :content, :description,
|
:file_name, :description,
|
||||||
:visibility_level, :created_at, :updated_at,
|
:visibility_level, :created_at, :updated_at,
|
||||||
:web_url, :raw_url, :notes, :discussions,
|
:web_url, :raw_url, :notes, :discussions,
|
||||||
:user_permissions, :description_html]
|
:user_permissions, :description_html, :blob]
|
||||||
|
|
||||||
is_expected.to have_graphql_fields(*expected_fields)
|
is_expected.to have_graphql_fields(*expected_fields)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe GitlabSchema.types['SnippetBlob'] do
|
||||||
|
it 'has the correct fields' do
|
||||||
|
expected_fields = [:highlighted_data, :raw_path,
|
||||||
|
:size, :binary, :name, :path,
|
||||||
|
:simple_viewer, :rich_viewer]
|
||||||
|
|
||||||
|
is_expected.to have_graphql_fields(*expected_fields)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe GitlabSchema.types['SnippetBlobViewer'] do
|
||||||
|
it 'has the correct fields' do
|
||||||
|
expected_fields = [:type, :load_async, :too_large, :collapsed,
|
||||||
|
:render_error, :file_type, :loading_partial_name]
|
||||||
|
|
||||||
|
is_expected.to have_graphql_fields(*expected_fields)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,84 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'fast_spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::SidekiqConfig::Worker do
|
||||||
|
def worker_with_queue(queue)
|
||||||
|
described_class.new(double(queue: queue), ee: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#ee?' do
|
||||||
|
it 'returns the EE status set on creation' do
|
||||||
|
expect(described_class.new(double, ee: true)).to be_ee
|
||||||
|
expect(described_class.new(double, ee: false)).not_to be_ee
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#==' do
|
||||||
|
def worker_with_yaml(yaml)
|
||||||
|
described_class.new(double, ee: false).tap do |worker|
|
||||||
|
allow(worker).to receive(:to_yaml).and_return(yaml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'defines two workers as equal if their YAML representations are equal' do
|
||||||
|
expect(worker_with_yaml('a')).to eq(worker_with_yaml('a'))
|
||||||
|
expect(worker_with_yaml('a')).not_to eq(worker_with_yaml('b'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true when a worker is compared with its YAML representation' do
|
||||||
|
expect(worker_with_yaml('a')).to eq('a')
|
||||||
|
expect(worker_with_yaml(a: 1, b: 2)).to eq(a: 1, b: 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'delegations' do
|
||||||
|
[
|
||||||
|
:feature_category_not_owned?, :get_feature_category,
|
||||||
|
:get_worker_resource_boundary, :latency_sensitive_worker?, :queue,
|
||||||
|
:worker_has_external_dependencies?
|
||||||
|
].each do |meth|
|
||||||
|
it "delegates #{meth} to the worker class" do
|
||||||
|
worker = double
|
||||||
|
|
||||||
|
expect(worker).to receive(meth)
|
||||||
|
|
||||||
|
described_class.new(worker, ee: false).send(meth)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'sorting' do
|
||||||
|
it 'sorts queues with a namespace before those without a namespace' do
|
||||||
|
namespaced_worker = worker_with_queue('namespace:queue')
|
||||||
|
plain_worker = worker_with_queue('a_queue')
|
||||||
|
|
||||||
|
expect([plain_worker, namespaced_worker].sort)
|
||||||
|
.to eq([namespaced_worker, plain_worker])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sorts alphabetically by queue' do
|
||||||
|
workers = [
|
||||||
|
worker_with_queue('namespace:a'),
|
||||||
|
worker_with_queue('namespace:b'),
|
||||||
|
worker_with_queue('other_namespace:a'),
|
||||||
|
worker_with_queue('other_namespace:b'),
|
||||||
|
worker_with_queue('a'),
|
||||||
|
worker_with_queue('b')
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(workers.shuffle.sort).to eq(workers)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'YAML encoding' do
|
||||||
|
it 'encodes the worker in YAML as a string of the queue' do
|
||||||
|
worker_a = worker_with_queue('a')
|
||||||
|
worker_b = worker_with_queue('b')
|
||||||
|
|
||||||
|
expect(YAML.dump(worker_a)).to eq(YAML.dump('a'))
|
||||||
|
expect(YAML.dump([worker_a, worker_b]))
|
||||||
|
.to eq(YAML.dump(%w[a b]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,10 +5,10 @@ require 'spec_helper'
|
||||||
describe Gitlab::SidekiqConfig do
|
describe Gitlab::SidekiqConfig do
|
||||||
describe '.workers' do
|
describe '.workers' do
|
||||||
it 'includes all workers' do
|
it 'includes all workers' do
|
||||||
workers = described_class.workers
|
worker_classes = described_class.workers.map(&:klass)
|
||||||
|
|
||||||
expect(workers).to include(PostReceive)
|
expect(worker_classes).to include(PostReceive)
|
||||||
expect(workers).to include(MergeWorker)
|
expect(worker_classes).to include(MergeWorker)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -44,4 +44,40 @@ describe Gitlab::SidekiqConfig do
|
||||||
expect(queues).to include('unknown')
|
expect(queues).to include('unknown')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.workers_for_all_queues_yml' do
|
||||||
|
it 'returns a tuple with FOSS workers first' do
|
||||||
|
expect(described_class.workers_for_all_queues_yml.first)
|
||||||
|
.to include(an_object_having_attributes(queue: 'post_receive'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.all_queues_yml_outdated?' do
|
||||||
|
before do
|
||||||
|
workers = [
|
||||||
|
PostReceive,
|
||||||
|
MergeWorker,
|
||||||
|
ProcessCommitWorker
|
||||||
|
].map { |worker| described_class::Worker.new(worker, ee: false) }
|
||||||
|
|
||||||
|
allow(described_class).to receive(:workers).and_return(workers)
|
||||||
|
allow(Gitlab).to receive(:ee?).and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true if the YAML file does not match the application code' do
|
||||||
|
allow(File).to receive(:read)
|
||||||
|
.with(described_class::FOSS_QUEUE_CONFIG_PATH)
|
||||||
|
.and_return(YAML.dump(%w[post_receive merge]))
|
||||||
|
|
||||||
|
expect(described_class.all_queues_yml_outdated?).to be(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false if the YAML file matches the application code' do
|
||||||
|
allow(File).to receive(:read)
|
||||||
|
.with(described_class::FOSS_QUEUE_CONFIG_PATH)
|
||||||
|
.and_return(YAML.dump(%w[merge post_receive process_commit]))
|
||||||
|
|
||||||
|
expect(described_class.all_queues_yml_outdated?).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe Sentry::Client::Issue do
|
||||||
let(:token) { 'test-token' }
|
let(:token) { 'test-token' }
|
||||||
let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' }
|
let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' }
|
||||||
let(:client) { Sentry::Client.new(sentry_url, token) }
|
let(:client) { Sentry::Client.new(sentry_url, token) }
|
||||||
let(:issue_id) { 503504 }
|
let(:issue_id) { 11 }
|
||||||
|
|
||||||
describe '#list_issues' do
|
describe '#list_issues' do
|
||||||
shared_examples 'issues have correct return type' do |klass|
|
shared_examples 'issues have correct return type' do |klass|
|
||||||
|
@ -243,7 +243,7 @@ describe Sentry::Client::Issue do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has a correct external URL' do
|
it 'has a correct external URL' do
|
||||||
expect(subject.external_url).to eq('https://sentrytest.gitlab.com/api/0/issues/503504')
|
expect(subject.external_url).to eq('https://sentrytest.gitlab.com/api/0/issues/11')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'issue has a correct external base url' do
|
it 'issue has a correct external base url' do
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe SnippetBlobPresenter do
|
||||||
|
describe '#highlighted_data' do
|
||||||
|
let(:snippet) { build(:personal_snippet) }
|
||||||
|
|
||||||
|
subject { described_class.new(snippet.blob).highlighted_data }
|
||||||
|
|
||||||
|
it 'returns nil when the snippet blob is binary' do
|
||||||
|
allow(snippet.blob).to receive(:binary?).and_return(true)
|
||||||
|
|
||||||
|
expect(subject).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns markdown content when snippet file is markup' do
|
||||||
|
snippet.file_name = 'test.md'
|
||||||
|
snippet.content = '*foo*'
|
||||||
|
|
||||||
|
expect(subject).to eq '<p data-sourcepos="1:1-1:5" dir="auto"><em>foo</em></p>'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns syntax highlighted content' do
|
||||||
|
snippet.file_name = 'test.rb'
|
||||||
|
snippet.content = 'class Foo;end'
|
||||||
|
|
||||||
|
expect(subject)
|
||||||
|
.to eq '<span id="LC1" class="line" lang="ruby"><span class="k">class</span> <span class="nc">Foo</span><span class="p">;</span><span class="k">end</span></span>'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns plain text highlighted content' do
|
||||||
|
snippet.file_name = 'test'
|
||||||
|
snippet.content = 'foo'
|
||||||
|
|
||||||
|
expect(described_class.new(snippet.blob).highlighted_data).to eq '<span id="LC1" class="line" lang="plaintext">foo</span>'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#raw_path' do
|
||||||
|
subject { described_class.new(snippet.blob).raw_path }
|
||||||
|
|
||||||
|
context 'with ProjectSnippet' do
|
||||||
|
let!(:project) { create(:project) }
|
||||||
|
let(:snippet) { build(:project_snippet, project: project, id: 1) }
|
||||||
|
|
||||||
|
it 'returns the raw path' do
|
||||||
|
expect(subject).to eq "/#{snippet.project.full_path}/snippets/1/raw"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with PersonalSnippet' do
|
||||||
|
let(:snippet) { build(:personal_snippet, id: 1) }
|
||||||
|
|
||||||
|
it 'returns the raw path' do
|
||||||
|
expect(subject).to eq "/snippets/1/raw"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -67,7 +67,7 @@ describe 'Creating a Snippet' do
|
||||||
it 'returns the created Snippet' do
|
it 'returns the created Snippet' do
|
||||||
post_graphql_mutation(mutation, current_user: current_user)
|
post_graphql_mutation(mutation, current_user: current_user)
|
||||||
|
|
||||||
expect(mutation_response['snippet']['content']).to eq(content)
|
expect(mutation_response['snippet']['blob']['highlightedData']).to match(content)
|
||||||
expect(mutation_response['snippet']['title']).to eq(title)
|
expect(mutation_response['snippet']['title']).to eq(title)
|
||||||
expect(mutation_response['snippet']['description']).to eq(description)
|
expect(mutation_response['snippet']['description']).to eq(description)
|
||||||
expect(mutation_response['snippet']['fileName']).to eq(file_name)
|
expect(mutation_response['snippet']['fileName']).to eq(file_name)
|
||||||
|
@ -92,7 +92,7 @@ describe 'Creating a Snippet' do
|
||||||
it 'returns the created Snippet' do
|
it 'returns the created Snippet' do
|
||||||
post_graphql_mutation(mutation, current_user: current_user)
|
post_graphql_mutation(mutation, current_user: current_user)
|
||||||
|
|
||||||
expect(mutation_response['snippet']['content']).to eq(content)
|
expect(mutation_response['snippet']['blob']['highlightedData']).to match(content)
|
||||||
expect(mutation_response['snippet']['title']).to eq(title)
|
expect(mutation_response['snippet']['title']).to eq(title)
|
||||||
expect(mutation_response['snippet']['description']).to eq(description)
|
expect(mutation_response['snippet']['description']).to eq(description)
|
||||||
expect(mutation_response['snippet']['fileName']).to eq(file_name)
|
expect(mutation_response['snippet']['fileName']).to eq(file_name)
|
||||||
|
|
|
@ -56,7 +56,7 @@ describe 'Updating a Snippet' do
|
||||||
it 'returns the updated Snippet' do
|
it 'returns the updated Snippet' do
|
||||||
post_graphql_mutation(mutation, current_user: current_user)
|
post_graphql_mutation(mutation, current_user: current_user)
|
||||||
|
|
||||||
expect(mutation_response['snippet']['content']).to eq(updated_content)
|
expect(mutation_response['snippet']['blob']['highlightedData']).to match(updated_content)
|
||||||
expect(mutation_response['snippet']['title']).to eq(updated_title)
|
expect(mutation_response['snippet']['title']).to eq(updated_title)
|
||||||
expect(mutation_response['snippet']['description']).to eq(updated_description)
|
expect(mutation_response['snippet']['description']).to eq(updated_description)
|
||||||
expect(mutation_response['snippet']['fileName']).to eq(updated_file_name)
|
expect(mutation_response['snippet']['fileName']).to eq(updated_file_name)
|
||||||
|
@ -77,7 +77,7 @@ describe 'Updating a Snippet' do
|
||||||
it 'returns the Snippet with its original values' do
|
it 'returns the Snippet with its original values' do
|
||||||
post_graphql_mutation(mutation, current_user: current_user)
|
post_graphql_mutation(mutation, current_user: current_user)
|
||||||
|
|
||||||
expect(mutation_response['snippet']['content']).to eq(original_content)
|
expect(mutation_response['snippet']['blob']['highlightedData']).to match(original_content)
|
||||||
expect(mutation_response['snippet']['title']).to eq(original_title)
|
expect(mutation_response['snippet']['title']).to eq(original_title)
|
||||||
expect(mutation_response['snippet']['description']).to eq(original_description)
|
expect(mutation_response['snippet']['description']).to eq(original_description)
|
||||||
expect(mutation_response['snippet']['fileName']).to eq(original_file_name)
|
expect(mutation_response['snippet']['fileName']).to eq(original_file_name)
|
||||||
|
|
|
@ -5,65 +5,9 @@ require 'spec_helper'
|
||||||
describe SubmitUsagePingService do
|
describe SubmitUsagePingService do
|
||||||
include StubRequests
|
include StubRequests
|
||||||
|
|
||||||
context 'when usage ping is disabled' do
|
let(:score_params) do
|
||||||
before do
|
|
||||||
stub_application_setting(usage_ping_enabled: false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not run' do
|
|
||||||
expect(HTTParty).not_to receive(:post)
|
|
||||||
|
|
||||||
result = subject.execute
|
|
||||||
|
|
||||||
expect(result).to eq false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when usage ping is enabled' do
|
|
||||||
before do
|
|
||||||
stub_application_setting(usage_ping_enabled: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'sends a POST request' do
|
|
||||||
response = stub_response(without_conv_index_params)
|
|
||||||
|
|
||||||
subject.execute
|
|
||||||
|
|
||||||
expect(response).to have_been_requested
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'refreshes usage data statistics before submitting' do
|
|
||||||
stub_response(without_conv_index_params)
|
|
||||||
|
|
||||||
expect(Gitlab::UsageData).to receive(:to_json)
|
|
||||||
.with(force_refresh: true)
|
|
||||||
.and_call_original
|
|
||||||
|
|
||||||
subject.execute
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'saves DevOps Score data from the response' do
|
|
||||||
stub_response(with_conv_index_params)
|
|
||||||
|
|
||||||
expect { subject.execute }
|
|
||||||
.to change { DevOpsScore::Metric.count }
|
|
||||||
.by(1)
|
|
||||||
|
|
||||||
expect(DevOpsScore::Metric.last.leader_issues).to eq 10.2
|
|
||||||
expect(DevOpsScore::Metric.last.instance_issues).to eq 3.2
|
|
||||||
expect(DevOpsScore::Metric.last.percentage_issues).to eq 31.37
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def without_conv_index_params
|
|
||||||
{
|
{
|
||||||
conv_index: {}
|
score: {
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def with_conv_index_params
|
|
||||||
{
|
|
||||||
conv_index: {
|
|
||||||
leader_issues: 10.2,
|
leader_issues: 10.2,
|
||||||
instance_issues: 3.2,
|
instance_issues: 3.2,
|
||||||
percentage_issues: 31.37,
|
percentage_issues: 31.37,
|
||||||
|
@ -100,6 +44,76 @@ describe SubmitUsagePingService do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:with_dev_ops_score_params) { { dev_ops_score: score_params[:score] } }
|
||||||
|
let(:with_conv_index_params) { { conv_index: score_params[:score] } }
|
||||||
|
let(:without_dev_ops_score_params) { { dev_ops_score: {} } }
|
||||||
|
|
||||||
|
context 'when usage ping is disabled' do
|
||||||
|
before do
|
||||||
|
stub_application_setting(usage_ping_enabled: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not run' do
|
||||||
|
expect(HTTParty).not_to receive(:post)
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result).to eq false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'saves DevOps score data from the response' do
|
||||||
|
it do
|
||||||
|
expect { subject.execute }
|
||||||
|
.to change { DevOpsScore::Metric.count }
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(DevOpsScore::Metric.last.leader_issues).to eq 10.2
|
||||||
|
expect(DevOpsScore::Metric.last.instance_issues).to eq 3.2
|
||||||
|
expect(DevOpsScore::Metric.last.percentage_issues).to eq 31.37
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when usage ping is enabled' do
|
||||||
|
before do
|
||||||
|
stub_application_setting(usage_ping_enabled: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends a POST request' do
|
||||||
|
response = stub_response(without_dev_ops_score_params)
|
||||||
|
|
||||||
|
subject.execute
|
||||||
|
|
||||||
|
expect(response).to have_been_requested
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'refreshes usage data statistics before submitting' do
|
||||||
|
stub_response(without_dev_ops_score_params)
|
||||||
|
|
||||||
|
expect(Gitlab::UsageData).to receive(:to_json)
|
||||||
|
.with(force_refresh: true)
|
||||||
|
.and_call_original
|
||||||
|
|
||||||
|
subject.execute
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when conv_index data is passed' do
|
||||||
|
before do
|
||||||
|
stub_response(with_conv_index_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'saves DevOps score data from the response'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when DevOps score data is passed' do
|
||||||
|
before do
|
||||||
|
stub_response(with_dev_ops_score_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'saves DevOps score data from the response'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def stub_response(body)
|
def stub_response(body)
|
||||||
stub_full_request('https://version.gitlab.com/usage_data', method: :post)
|
stub_full_request('https://version.gitlab.com/usage_data', method: :post)
|
||||||
.to_return(
|
.to_return(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# This matcher checkes if one spam log with provided attributes was created
|
# This matcher checks if one spam log with provided attributes was created
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
shared_context 'sentry error tracking context feature' do
|
||||||
|
include ReactiveCachingHelpers
|
||||||
|
|
||||||
|
let_it_be(:project) { create(:project) }
|
||||||
|
let_it_be(:project_error_tracking_settings) { create(:project_error_tracking_setting, project: project) }
|
||||||
|
let_it_be(:issue_response_body) { fixture_file('sentry/issue_sample_response.json') }
|
||||||
|
let_it_be(:issue_response) { JSON.parse(issue_response_body) }
|
||||||
|
let_it_be(:event_response_body) { fixture_file('sentry/issue_latest_event_sample_response.json') }
|
||||||
|
let_it_be(:event_response) { JSON.parse(event_response_body) }
|
||||||
|
let(:sentry_api_urls) { Sentry::ApiUrls.new(project_error_tracking_settings.api_url) }
|
||||||
|
let(:issue_id) { issue_response['id'] }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:get, sentry_api_urls.issue_url(issue_id)).with(
|
||||||
|
headers: { 'Authorization' => 'Bearer access_token_123' }
|
||||||
|
).to_return(status: 200, body: issue_response_body, headers: { 'Content-Type' => 'application/json' })
|
||||||
|
stub_request(:get, sentry_api_urls.issue_latest_event_url(issue_id)).with(
|
||||||
|
headers: { 'Authorization' => 'Bearer access_token_123' }
|
||||||
|
).to_return(status: 200, body: event_response_body, headers: { 'Content-Type' => 'application/json' })
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,86 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
shared_examples 'error tracking index page' do
|
||||||
|
it 'renders the error index page' do
|
||||||
|
within('div.js-title-container') do
|
||||||
|
expect(page).to have_content(project.namespace.name)
|
||||||
|
expect(page).to have_content(project.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
within('div.error-list') do
|
||||||
|
expect(page).to have_content('Error')
|
||||||
|
expect(page).to have_content('Events')
|
||||||
|
expect(page).to have_content('Users')
|
||||||
|
expect(page).to have_content('Last Seen')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the error index data' do
|
||||||
|
Timecop.freeze(2020, 01, 01, 12, 0, 0) do
|
||||||
|
within('div.error-list') do
|
||||||
|
expect(page).to have_content(issues_response[0]['title'])
|
||||||
|
expect(page).to have_content(issues_response[0]['count'].to_s)
|
||||||
|
expect(page).to have_content(issues_response[0]['last_seen'])
|
||||||
|
expect(page).to have_content('1 year ago')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when error is clicked' do
|
||||||
|
before do
|
||||||
|
click_on issues_response[0]['title']
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'loads the error page' do
|
||||||
|
expect(page).to have_content('Error details')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'expanded stack trace context' do |selected_line: nil, expected_line: 1|
|
||||||
|
it 'expands the stack trace context' do
|
||||||
|
within('div.stacktrace') do
|
||||||
|
find("div.file-holder:nth-child(#{selected_line}) svg.ic-chevron-right").click if selected_line
|
||||||
|
|
||||||
|
expanded_line = find("div.file-holder:nth-child(#{expected_line})")
|
||||||
|
expect(expanded_line).to have_css('svg.ic-chevron-down')
|
||||||
|
|
||||||
|
event_response['entries'][0]['data']['values'][0]['stacktrace']['frames'][-expected_line]['context'].each do |context|
|
||||||
|
expect(page).to have_content(context[0])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'error tracking show page' do
|
||||||
|
it 'renders the error details' do
|
||||||
|
release_short_version = issue_response['firstRelease']['shortVersion']
|
||||||
|
|
||||||
|
Timecop.freeze(2020, 01, 01, 12, 0, 0) do
|
||||||
|
expect(page).to have_content('1 month ago by raven.scripts.runner in main')
|
||||||
|
expect(page).to have_content(issue_response['metadata']['title'])
|
||||||
|
expect(page).to have_content('level: error')
|
||||||
|
expect(page).to have_content('Error details')
|
||||||
|
expect(page).to have_content('GitLab Issue: https://gitlab.com/gitlab-org/gitlab/issues/1')
|
||||||
|
expect(page).to have_content("Sentry event: https://sentrytest.gitlab.com/sentry-org/sentry-project/issues/#{issue_id}")
|
||||||
|
expect(page).to have_content("First seen: 1 year ago (2018-11-06 9:19:55PM UTC) Release: #{release_short_version}")
|
||||||
|
expect(page).to have_content('Events: 1')
|
||||||
|
expect(page).to have_content('Users: 0')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the stack trace heading' do
|
||||||
|
expect(page).to have_content('Stack trace')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the stack trace' do
|
||||||
|
event_response['entries'][0]['data']['values'][0]['stacktrace']['frames'].each do |frame|
|
||||||
|
expect(frame['filename']).not_to be_nil
|
||||||
|
expect(page).to have_content(frame['filename'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# The first line is expanded by default if no line is selected
|
||||||
|
it_behaves_like 'expanded stack trace context', selected_line: nil, expected_line: 1
|
||||||
|
it_behaves_like 'expanded stack trace context', selected_line: 8, expected_line: 8
|
||||||
|
end
|
|
@ -3,8 +3,12 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe 'Every Sidekiq worker' do
|
describe 'Every Sidekiq worker' do
|
||||||
|
let(:workers_without_defaults) do
|
||||||
|
Gitlab::SidekiqConfig.workers - Gitlab::SidekiqConfig::DEFAULT_WORKERS
|
||||||
|
end
|
||||||
|
|
||||||
it 'does not use the default queue' do
|
it 'does not use the default queue' do
|
||||||
expect(Gitlab::SidekiqConfig.workers.map(&:queue)).not_to include('default')
|
expect(workers_without_defaults.map(&:queue)).not_to include('default')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'uses the cronjob queue when the worker runs as a cronjob' do
|
it 'uses the cronjob queue when the worker runs as a cronjob' do
|
||||||
|
@ -45,7 +49,7 @@ describe 'Every Sidekiq worker' do
|
||||||
# or explicitly be excluded with the `feature_category_not_owned!` annotation.
|
# or explicitly be excluded with the `feature_category_not_owned!` annotation.
|
||||||
# Please see doc/development/sidekiq_style_guide.md#Feature-Categorization for more details.
|
# Please see doc/development/sidekiq_style_guide.md#Feature-Categorization for more details.
|
||||||
it 'has a feature_category or feature_category_not_owned! attribute', :aggregate_failures do
|
it 'has a feature_category or feature_category_not_owned! attribute', :aggregate_failures do
|
||||||
Gitlab::SidekiqConfig.workers.each do |worker|
|
workers_without_defaults.each do |worker|
|
||||||
expect(worker.get_feature_category).to be_a(Symbol), "expected #{worker.inspect} to declare a feature_category or feature_category_not_owned!"
|
expect(worker.get_feature_category).to be_a(Symbol), "expected #{worker.inspect} to declare a feature_category or feature_category_not_owned!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -54,7 +58,7 @@ describe 'Every Sidekiq worker' do
|
||||||
# The category should match a value in `config/feature_categories.yml`.
|
# The category should match a value in `config/feature_categories.yml`.
|
||||||
# Please see doc/development/sidekiq_style_guide.md#Feature-Categorization for more details.
|
# Please see doc/development/sidekiq_style_guide.md#Feature-Categorization for more details.
|
||||||
it 'has a feature_category that maps to a value in feature_categories.yml', :aggregate_failures do
|
it 'has a feature_category that maps to a value in feature_categories.yml', :aggregate_failures do
|
||||||
workers_with_feature_categories = Gitlab::SidekiqConfig.workers
|
workers_with_feature_categories = workers_without_defaults
|
||||||
.select(&:get_feature_category)
|
.select(&:get_feature_category)
|
||||||
.reject(&:feature_category_not_owned?)
|
.reject(&:feature_category_not_owned?)
|
||||||
|
|
||||||
|
@ -69,7 +73,7 @@ describe 'Every Sidekiq worker' do
|
||||||
# rather than scaling the hardware to meet the SLO. For this reason, memory-bound,
|
# rather than scaling the hardware to meet the SLO. For this reason, memory-bound,
|
||||||
# latency-sensitive jobs are explicitly discouraged and disabled.
|
# latency-sensitive jobs are explicitly discouraged and disabled.
|
||||||
it 'is (exclusively) memory-bound or latency-sentitive, not both', :aggregate_failures do
|
it 'is (exclusively) memory-bound or latency-sentitive, not both', :aggregate_failures do
|
||||||
latency_sensitive_workers = Gitlab::SidekiqConfig.workers
|
latency_sensitive_workers = workers_without_defaults
|
||||||
.select(&:latency_sensitive_worker?)
|
.select(&:latency_sensitive_worker?)
|
||||||
|
|
||||||
latency_sensitive_workers.each do |worker|
|
latency_sensitive_workers.each do |worker|
|
||||||
|
@ -86,7 +90,7 @@ describe 'Every Sidekiq worker' do
|
||||||
# Please see doc/development/sidekiq_style_guide.md#Jobs-with-External-Dependencies for more
|
# Please see doc/development/sidekiq_style_guide.md#Jobs-with-External-Dependencies for more
|
||||||
# details.
|
# details.
|
||||||
it 'has (exclusively) external dependencies or is latency-sentitive, not both', :aggregate_failures do
|
it 'has (exclusively) external dependencies or is latency-sentitive, not both', :aggregate_failures do
|
||||||
latency_sensitive_workers = Gitlab::SidekiqConfig.workers
|
latency_sensitive_workers = workers_without_defaults
|
||||||
.select(&:latency_sensitive_worker?)
|
.select(&:latency_sensitive_worker?)
|
||||||
|
|
||||||
latency_sensitive_workers.each do |worker|
|
latency_sensitive_workers.each do |worker|
|
||||||
|
|
119
yarn.lock
119
yarn.lock
|
@ -655,9 +655,9 @@
|
||||||
semver "^5.5.0"
|
semver "^5.5.0"
|
||||||
|
|
||||||
"@babel/standalone@^7.0.0":
|
"@babel/standalone@^7.0.0":
|
||||||
version "7.5.5"
|
version "7.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.5.5.tgz#9d3143f6078ff408db694a4254bd6f03c5c33962"
|
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.8.3.tgz#0674730a8c5fbb9352de5342bf0c0c040d658380"
|
||||||
integrity sha512-YIp5taErC4uvp4d5urJtWMui3cpvZt83x57l4oVJNvFtDzumf3pMgRmoTSpGuEzh1yzo7jHhg3mbQmMhmKPbjA==
|
integrity sha512-WRYZUuGBYpmfUL50f2h3Cvw7s1F4wTVT5iIeT01tHo+LyB9QwrTJ6GF5J6YrtJHQqxMxt8zEl1d7I0Uhyz9NyQ==
|
||||||
|
|
||||||
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
|
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
|
||||||
version "7.6.0"
|
version "7.6.0"
|
||||||
|
@ -737,10 +737,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.89.0.tgz#5bdaff1b0af1cc07ed34e89c21c34c7c6a3e1caa"
|
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.89.0.tgz#5bdaff1b0af1cc07ed34e89c21c34c7c6a3e1caa"
|
||||||
integrity sha512-vI6VobZs6mq2Bbiej5bYMHyvtn8kD1O/uHSlyY9jgJoa2TXU+jFI9DqUpJmx8EIHt+o0qm/8G3XsFGEr5gLb7Q==
|
integrity sha512-vI6VobZs6mq2Bbiej5bYMHyvtn8kD1O/uHSlyY9jgJoa2TXU+jFI9DqUpJmx8EIHt+o0qm/8G3XsFGEr5gLb7Q==
|
||||||
|
|
||||||
"@gitlab/ui@8.17.0":
|
"@gitlab/ui@^8.18.0":
|
||||||
version "8.17.0"
|
version "8.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-8.17.0.tgz#674baa9b5c05fa6ecb23b233c5b308ff82ba5660"
|
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-8.18.0.tgz#11bd7d5fb2db10034fdf2544847dc9afd24cc02c"
|
||||||
integrity sha512-klWzMFU3IdoLUgRP6OTYUyO+EDfckG9/cphPKVBaf0MLx4HpjiW5LwGW3stL3A9SlyauCwAZOLkqbJKbN5pxCQ==
|
integrity sha512-ihcXJDVUNvp8kv+ha+0d1rrRIG8IEWfDNICremTpl62V5kN9Eiwo0Csb8Gj20sBp9ERYCycjwpjvfU7dUwyAiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/standalone" "^7.0.0"
|
"@babel/standalone" "^7.0.0"
|
||||||
"@gitlab/vue-toasted" "^1.3.0"
|
"@gitlab/vue-toasted" "^1.3.0"
|
||||||
|
@ -1168,6 +1168,21 @@
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
vue-template-es2015-compiler "^1.9.0"
|
vue-template-es2015-compiler "^1.9.0"
|
||||||
|
|
||||||
|
"@vue/component-compiler-utils@^3.1.0":
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.1.1.tgz#d4ef8f80292674044ad6211e336a302e4d2a6575"
|
||||||
|
integrity sha512-+lN3nsfJJDGMNz7fCpcoYIORrXo0K3OTsdr8jCM7FuqdI4+70TY6gxY6viJ2Xi1clqyPg7LpeOWwjF31vSMmUw==
|
||||||
|
dependencies:
|
||||||
|
consolidate "^0.15.1"
|
||||||
|
hash-sum "^1.0.2"
|
||||||
|
lru-cache "^4.1.2"
|
||||||
|
merge-source-map "^1.1.0"
|
||||||
|
postcss "^7.0.14"
|
||||||
|
postcss-selector-parser "^6.0.2"
|
||||||
|
prettier "^1.18.2"
|
||||||
|
source-map "~0.6.1"
|
||||||
|
vue-template-es2015-compiler "^1.9.0"
|
||||||
|
|
||||||
"@vue/test-utils@^1.0.0-beta.30":
|
"@vue/test-utils@^1.0.0-beta.30":
|
||||||
version "1.0.0-beta.30"
|
version "1.0.0-beta.30"
|
||||||
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.30.tgz#d5f26d1e2411fdb7fa7fdedb61b4b4ea4194c49d"
|
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.30.tgz#d5f26d1e2411fdb7fa7fdedb61b4b4ea4194c49d"
|
||||||
|
@ -2072,11 +2087,16 @@ bootstrap-vue@2.0.0-rc.27:
|
||||||
portal-vue "^2.1.5"
|
portal-vue "^2.1.5"
|
||||||
vue-functional-data-merge "^3.1.0"
|
vue-functional-data-merge "^3.1.0"
|
||||||
|
|
||||||
bootstrap@4.3.1, bootstrap@^4.3.1:
|
bootstrap@4.3.1:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
|
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
|
||||||
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
|
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
|
||||||
|
|
||||||
|
bootstrap@^4.3.1:
|
||||||
|
version "4.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
|
||||||
|
integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
|
||||||
|
|
||||||
boxen@^1.2.1:
|
boxen@^1.2.1:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
|
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
|
||||||
|
@ -2894,9 +2914,9 @@ connect@^3.6.0:
|
||||||
utils-merge "1.0.1"
|
utils-merge "1.0.1"
|
||||||
|
|
||||||
consola@^2.3.0:
|
consola@^2.3.0:
|
||||||
version "2.9.0"
|
version "2.11.3"
|
||||||
resolved "https://registry.yarnpkg.com/consola/-/consola-2.9.0.tgz#57760e3a65a53ec27337f4add31505802d902278"
|
resolved "https://registry.yarnpkg.com/consola/-/consola-2.11.3.tgz#f7315836224c143ac5094b47fd4c816c2cd1560e"
|
||||||
integrity sha512-34Iue+LRcWbndFIfZc5boNizWlsrRjqIBJZTe591vImgbnq7nx2EzlrLtANj9TH2Fxm7puFJBJAOk5BhvZOddQ==
|
integrity sha512-aoW0YIIAmeftGR8GSpw6CGQluNdkWMWh3yEFjH/hmynTYnMtibXszii3lxCXmk8YxJtI3FAK5aTiquA5VH68Gw==
|
||||||
|
|
||||||
console-browserify@^1.1.0:
|
console-browserify@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
@ -2979,11 +2999,11 @@ copy-descriptor@^0.1.0:
|
||||||
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
|
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
|
||||||
|
|
||||||
copy-to-clipboard@^3.0.8:
|
copy-to-clipboard@^3.0.8:
|
||||||
version "3.0.8"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9"
|
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.2.0.tgz#d2724a3ccbfed89706fac8a894872c979ac74467"
|
||||||
integrity sha512-c3GdeY8qxCHGezVb1EFQfHYK/8NZRemgcTIzPq7PuxjHAf/raKibn2QdhHPb/y6q74PMgH6yizaDZlRmw6QyKw==
|
integrity sha512-eOZERzvCmxS8HWzugj4Uxl8OJxa7T2k1Gi0X5qavwydHIfuSHq2dTD09LOg/XyGq4Zpb5IsR/2OJ5lbOegz78w==
|
||||||
dependencies:
|
dependencies:
|
||||||
toggle-selection "^1.0.3"
|
toggle-selection "^1.0.6"
|
||||||
|
|
||||||
copy-webpack-plugin@^5.0.4:
|
copy-webpack-plugin@^5.0.4:
|
||||||
version "5.0.4"
|
version "5.0.4"
|
||||||
|
@ -3993,11 +4013,11 @@ ecc-jsbn@~0.1.1:
|
||||||
safer-buffer "^2.1.0"
|
safer-buffer "^2.1.0"
|
||||||
|
|
||||||
echarts@^4.2.1:
|
echarts@^4.2.1:
|
||||||
version "4.2.1"
|
version "4.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/echarts/-/echarts-4.2.1.tgz#9a8ea3b03354f86f824d97625c334cf16965ef03"
|
resolved "https://registry.yarnpkg.com/echarts/-/echarts-4.6.0.tgz#b5a47a1046cec93ceeef954f9ee54751340558ec"
|
||||||
integrity sha512-pw4xScRPsLegD/cqEcoXRKeA2SD4+s+Kyo0Na166NamOWhzNl2yI5RZ2rE97tBlAopNmhyMeBVpAeD5qb+ee1A==
|
integrity sha512-xKkcr6v9UVOSF+PMuj7Ngt3bnzLwN1sSXWCvpvX+jYb3mePYsZnABq7wGkPac/m0nV653uGHXoHK8DCKCprdNg==
|
||||||
dependencies:
|
dependencies:
|
||||||
zrender "4.0.7"
|
zrender "4.2.0"
|
||||||
|
|
||||||
editions@^1.3.3:
|
editions@^1.3.3:
|
||||||
version "1.3.4"
|
version "1.3.4"
|
||||||
|
@ -5500,7 +5520,12 @@ he@^1.1.0, he@^1.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||||
|
|
||||||
highlight.js@^9.13.1, highlight.js@~9.13.0:
|
highlight.js@^9.13.1:
|
||||||
|
version "9.18.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.0.tgz#6b1763cfcd53744313bd3f31f1210f7beb962c79"
|
||||||
|
integrity sha512-A97kI1KAUzKoAiEoaGcf2O9YPS8nbDTCRFokaaeBhnqjQTvbAuAJrQMm21zw8s8xzaMtCQBtgbyGXLGxdxQyqQ==
|
||||||
|
|
||||||
|
highlight.js@~9.13.0:
|
||||||
version "9.13.1"
|
version "9.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e"
|
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e"
|
||||||
integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==
|
integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==
|
||||||
|
@ -6778,7 +6803,7 @@ js-base64@^2.1.8:
|
||||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
|
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
|
||||||
integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
|
integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
|
||||||
|
|
||||||
js-beautify@^1.6.12, js-beautify@^1.8.8:
|
js-beautify@^1.6.12:
|
||||||
version "1.10.2"
|
version "1.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.2.tgz#88c9099cd6559402b124cfab18754936f8a7b178"
|
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.2.tgz#88c9099cd6559402b124cfab18754936f8a7b178"
|
||||||
integrity sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ==
|
integrity sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ==
|
||||||
|
@ -6789,6 +6814,17 @@ js-beautify@^1.6.12, js-beautify@^1.8.8:
|
||||||
mkdirp "~0.5.1"
|
mkdirp "~0.5.1"
|
||||||
nopt "~4.0.1"
|
nopt "~4.0.1"
|
||||||
|
|
||||||
|
js-beautify@^1.8.8:
|
||||||
|
version "1.10.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.3.tgz#c73fa10cf69d3dfa52d8ed624f23c64c0a6a94c1"
|
||||||
|
integrity sha512-wfk/IAWobz1TfApSdivH5PJ0miIHgDoYb1ugSqHcODPmaYu46rYe5FVuIEkhjg8IQiv6rDNPyhsqbsohI/C2vQ==
|
||||||
|
dependencies:
|
||||||
|
config-chain "^1.1.12"
|
||||||
|
editorconfig "^0.15.3"
|
||||||
|
glob "^7.1.3"
|
||||||
|
mkdirp "~0.5.1"
|
||||||
|
nopt "~4.0.1"
|
||||||
|
|
||||||
js-cookie@^2.1.3:
|
js-cookie@^2.1.3:
|
||||||
version "2.1.3"
|
version "2.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.1.3.tgz#48071625217ac9ecfab8c343a13d42ec09ff0526"
|
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.1.3.tgz#48071625217ac9ecfab8c343a13d42ec09ff0526"
|
||||||
|
@ -8800,11 +8836,16 @@ pofile@^1:
|
||||||
resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
|
resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
|
||||||
integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==
|
integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==
|
||||||
|
|
||||||
popper.js@^1.14.7, popper.js@^1.15.0:
|
popper.js@^1.14.7:
|
||||||
version "1.15.0"
|
version "1.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2"
|
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2"
|
||||||
integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==
|
integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==
|
||||||
|
|
||||||
|
popper.js@^1.15.0:
|
||||||
|
version "1.16.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.0.tgz#2e1816bcbbaa518ea6c2e15a466f4cb9c6e2fbb3"
|
||||||
|
integrity sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw==
|
||||||
|
|
||||||
portal-vue@^2.1.5, portal-vue@^2.1.6:
|
portal-vue@^2.1.5, portal-vue@^2.1.6:
|
||||||
version "2.1.7"
|
version "2.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.7.tgz#ea08069b25b640ca08a5b86f67c612f15f4e4ad4"
|
resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.7.tgz#ea08069b25b640ca08a5b86f67c612f15f4e4ad4"
|
||||||
|
@ -9006,6 +9047,11 @@ prettier@1.18.2:
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
|
||||||
integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==
|
integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==
|
||||||
|
|
||||||
|
prettier@^1.18.2:
|
||||||
|
version "1.19.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||||
|
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
|
||||||
|
|
||||||
pretty-format@^24.8.0:
|
pretty-format@^24.8.0:
|
||||||
version "24.8.0"
|
version "24.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2"
|
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2"
|
||||||
|
@ -11113,7 +11159,7 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
||||||
regex-not "^1.0.2"
|
regex-not "^1.0.2"
|
||||||
safe-regex "^1.1.0"
|
safe-regex "^1.1.0"
|
||||||
|
|
||||||
toggle-selection@^1.0.3:
|
toggle-selection@^1.0.6:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
|
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
|
||||||
integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI=
|
integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI=
|
||||||
|
@ -11525,9 +11571,9 @@ url-parse@^1.4.3:
|
||||||
requires-port "^1.0.0"
|
requires-port "^1.0.0"
|
||||||
|
|
||||||
url-search-params-polyfill@^5.0.0:
|
url-search-params-polyfill@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/url-search-params-polyfill/-/url-search-params-polyfill-5.0.0.tgz#09b98337c89dcf6c6a6a0bfeb096f6ba83b7526b"
|
resolved "https://registry.yarnpkg.com/url-search-params-polyfill/-/url-search-params-polyfill-5.1.0.tgz#f0405dcc2e921bf7f5fdf8c4e616f1e8088ef31b"
|
||||||
integrity sha512-+SCD22QJp4UnqPOI5UTTR0Ljuh8cHbjEf1lIiZrZ8nHTlTixqwVsVQTSfk5vrmDz7N09/Y+ka5jQr0ff35FnQQ==
|
integrity sha512-yjFY7uw2xRf9e8Mg4ZVkZwtp8dMCC4cbBkEIZiTDpuSY2WJ9+Quw0wRhxncv32qaMQwmBQT+P847rO8PrFhhDA==
|
||||||
|
|
||||||
url@0.10.3:
|
url@0.10.3:
|
||||||
version "0.10.3"
|
version "0.10.3"
|
||||||
|
@ -11713,7 +11759,18 @@ vue-jest@^4.0.0-beta.2:
|
||||||
source-map "^0.5.6"
|
source-map "^0.5.6"
|
||||||
ts-jest "^23.10.5"
|
ts-jest "^23.10.5"
|
||||||
|
|
||||||
vue-loader@^15.4.2, vue-loader@^15.7.1:
|
vue-loader@^15.4.2:
|
||||||
|
version "15.8.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.8.3.tgz#857cb9e30eb5fc25e66db48dce7e4f768602a23c"
|
||||||
|
integrity sha512-yFksTFbhp+lxlm92DrKdpVIWMpranXnTEuGSc0oW+Gk43M9LWaAmBTnfj5+FCdve715mTHvo78IdaXf5TbiTJg==
|
||||||
|
dependencies:
|
||||||
|
"@vue/component-compiler-utils" "^3.1.0"
|
||||||
|
hash-sum "^1.0.2"
|
||||||
|
loader-utils "^1.1.0"
|
||||||
|
vue-hot-reload-api "^2.3.0"
|
||||||
|
vue-style-loader "^4.1.0"
|
||||||
|
|
||||||
|
vue-loader@^15.7.1:
|
||||||
version "15.7.1"
|
version "15.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.1.tgz#6ccacd4122aa80f69baaac08ff295a62e3aefcfd"
|
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.1.tgz#6ccacd4122aa80f69baaac08ff295a62e3aefcfd"
|
||||||
integrity sha512-fwIKtA23Pl/rqfYP5TSGK7gkEuLhoTvRYW+TU7ER3q9GpNLt/PjG5NLv3XHRDiTg7OPM1JcckBgds+VnAc+HbA==
|
integrity sha512-fwIKtA23Pl/rqfYP5TSGK7gkEuLhoTvRYW+TU7ER3q9GpNLt/PjG5NLv3XHRDiTg7OPM1JcckBgds+VnAc+HbA==
|
||||||
|
@ -12308,7 +12365,7 @@ zen-observable@^0.8.0:
|
||||||
resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.11.tgz#d3415885eeeb42ee5abb9821c95bb518fcd6d199"
|
resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.11.tgz#d3415885eeeb42ee5abb9821c95bb518fcd6d199"
|
||||||
integrity sha512-N3xXQVr4L61rZvGMpWe8XoCGX8vhU35dPyQ4fm5CY/KDlG0F75un14hjbckPXTDuKUY6V0dqR2giT6xN8Y4GEQ==
|
integrity sha512-N3xXQVr4L61rZvGMpWe8XoCGX8vhU35dPyQ4fm5CY/KDlG0F75un14hjbckPXTDuKUY6V0dqR2giT6xN8Y4GEQ==
|
||||||
|
|
||||||
zrender@4.0.7:
|
zrender@4.2.0:
|
||||||
version "4.0.7"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/zrender/-/zrender-4.0.7.tgz#15ae960822f5efed410995d37e5107fe3de10e6d"
|
resolved "https://registry.yarnpkg.com/zrender/-/zrender-4.2.0.tgz#d001302e155f28de1f9fc7fcd5c254bad28471cf"
|
||||||
integrity sha512-TNloHe0ums6zxbHfnaCryM61J4IWDajZwNq6dHk9vfWhhysO/OeFvvR0drBs/nbXha2YxSzfQj2FiCd6RVBe+Q==
|
integrity sha512-YJ9hxt5uFincYYU3KK31+Ce+B6PJmYYK0Q9fQ6jOUAoC/VHbe4kCKAPkxKeT7jGTxrK5wYu18R0TLGqj2zbEOA==
|
||||||
|
|
Loading…
Reference in New Issue