Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
11e5d1b9ca
commit
c57e10faab
36 changed files with 404 additions and 229 deletions
3
Gemfile
3
Gemfile
|
@ -381,8 +381,6 @@ group :development, :test do
|
||||||
|
|
||||||
gem 'knapsack', '~> 1.17'
|
gem 'knapsack', '~> 1.17'
|
||||||
|
|
||||||
gem 'stackprof', '~> 0.2.13', require: false
|
|
||||||
|
|
||||||
gem 'simple_po_parser', '~> 1.1.2', require: false
|
gem 'simple_po_parser', '~> 1.1.2', require: false
|
||||||
|
|
||||||
gem 'timecop', '~> 0.8.0'
|
gem 'timecop', '~> 0.8.0'
|
||||||
|
@ -427,6 +425,7 @@ gem 'email_reply_trimmer', '~> 0.1'
|
||||||
gem 'html2text'
|
gem 'html2text'
|
||||||
|
|
||||||
gem 'ruby-prof', '~> 1.0.0'
|
gem 'ruby-prof', '~> 1.0.0'
|
||||||
|
gem 'stackprof', '~> 0.2.15', require: false
|
||||||
gem 'rbtrace', '~> 0.4', require: false
|
gem 'rbtrace', '~> 0.4', require: false
|
||||||
gem 'memory_profiler', '~> 0.9', require: false
|
gem 'memory_profiler', '~> 0.9', require: false
|
||||||
gem 'benchmark-memory', '~> 0.1', require: false
|
gem 'benchmark-memory', '~> 0.1', require: false
|
||||||
|
|
|
@ -1037,7 +1037,7 @@ GEM
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sqlite3 (1.3.13)
|
sqlite3 (1.3.13)
|
||||||
sshkey (2.0.0)
|
sshkey (2.0.0)
|
||||||
stackprof (0.2.13)
|
stackprof (0.2.15)
|
||||||
state_machines (0.5.0)
|
state_machines (0.5.0)
|
||||||
state_machines-activemodel (0.7.1)
|
state_machines-activemodel (0.7.1)
|
||||||
activemodel (>= 4.1)
|
activemodel (>= 4.1)
|
||||||
|
@ -1382,7 +1382,7 @@ DEPENDENCIES
|
||||||
spring-commands-rspec (~> 1.0.4)
|
spring-commands-rspec (~> 1.0.4)
|
||||||
sprockets (~> 3.7.0)
|
sprockets (~> 3.7.0)
|
||||||
sshkey (~> 2.0)
|
sshkey (~> 2.0)
|
||||||
stackprof (~> 0.2.13)
|
stackprof (~> 0.2.15)
|
||||||
state_machines-activerecord (~> 0.6.0)
|
state_machines-activerecord (~> 0.6.0)
|
||||||
sys-filesystem (~> 1.1.6)
|
sys-filesystem (~> 1.1.6)
|
||||||
test-prof (~> 0.10.0)
|
test-prof (~> 0.10.0)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
|
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
|
||||||
import { mapActions, mapState, mapGetters } from 'vuex';
|
import { mapActions, mapState, mapGetters } from 'vuex';
|
||||||
import IdeStatusList from 'ee_else_ce/ide/components/ide_status_list.vue';
|
import IdeStatusList from 'ee_else_ce/ide/components/ide_status_list.vue';
|
||||||
|
import IdeStatusMr from './ide_status_mr.vue';
|
||||||
import icon from '~/vue_shared/components/icon.vue';
|
import icon from '~/vue_shared/components/icon.vue';
|
||||||
import tooltip from '~/vue_shared/directives/tooltip';
|
import tooltip from '~/vue_shared/directives/tooltip';
|
||||||
import timeAgoMixin from '~/vue_shared/mixins/timeago';
|
import timeAgoMixin from '~/vue_shared/mixins/timeago';
|
||||||
|
@ -15,6 +16,7 @@ export default {
|
||||||
userAvatarImage,
|
userAvatarImage,
|
||||||
CiIcon,
|
CiIcon,
|
||||||
IdeStatusList,
|
IdeStatusList,
|
||||||
|
IdeStatusMr,
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
tooltip,
|
tooltip,
|
||||||
|
@ -27,7 +29,7 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['currentBranchId', 'currentProjectId']),
|
...mapState(['currentBranchId', 'currentProjectId']),
|
||||||
...mapGetters(['currentProject', 'lastCommit']),
|
...mapGetters(['currentProject', 'lastCommit', 'currentMergeRequest']),
|
||||||
...mapState('pipelines', ['latestPipeline']),
|
...mapState('pipelines', ['latestPipeline']),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -121,6 +123,12 @@ export default {
|
||||||
>{{ lastCommitFormattedAge }}</time
|
>{{ lastCommitFormattedAge }}</time
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
<ide-status-mr
|
||||||
|
v-if="currentMergeRequest"
|
||||||
|
class="mx-3"
|
||||||
|
:url="currentMergeRequest.web_url"
|
||||||
|
:text="currentMergeRequest.references.short"
|
||||||
|
/>
|
||||||
<ide-status-list class="ml-auto" />
|
<ide-status-list class="ml-auto" />
|
||||||
</footer>
|
</footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
28
app/assets/javascripts/ide/components/ide_status_mr.vue
Normal file
28
app/assets/javascripts/ide/components/ide_status_mr.vue
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<script>
|
||||||
|
import { GlIcon, GlLink } from '@gitlab/ui';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
GlIcon,
|
||||||
|
GlLink,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="d-flex-center flex-nowrap text-nowrap js-ide-status-mr">
|
||||||
|
<gl-icon name="merge-request" />
|
||||||
|
<span class="ml-1 d-none d-sm-block">{{ s__('WebIDE|Merge request') }}</span>
|
||||||
|
<gl-link class="ml-1" :href="url">{{ text }}</gl-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -1,38 +0,0 @@
|
||||||
<script>
|
|
||||||
import { mapGetters } from 'vuex';
|
|
||||||
import Icon from '../../../vue_shared/components/icon.vue';
|
|
||||||
import TitleComponent from '../../../issue_show/components/title.vue';
|
|
||||||
import DescriptionComponent from '../../../issue_show/components/description.vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
Icon,
|
|
||||||
TitleComponent,
|
|
||||||
DescriptionComponent,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters(['currentMergeRequest']),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="ide-merge-request-info h-100 d-flex flex-column">
|
|
||||||
<div class="detail-page-header">
|
|
||||||
<icon name="git-merge" class="align-self-center append-right-8" />
|
|
||||||
<strong> !{{ currentMergeRequest.iid }} </strong>
|
|
||||||
</div>
|
|
||||||
<div class="issuable-details">
|
|
||||||
<title-component
|
|
||||||
:issuable-ref="currentMergeRequest.iid"
|
|
||||||
:title-html="currentMergeRequest.title_html"
|
|
||||||
:title-text="currentMergeRequest.title"
|
|
||||||
/>
|
|
||||||
<description-component
|
|
||||||
:description-html="currentMergeRequest.description_html"
|
|
||||||
:description-text="currentMergeRequest.description"
|
|
||||||
:can-update="false"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
|
@ -3,7 +3,6 @@ import { mapGetters, mapState } from 'vuex';
|
||||||
import { __ } from '~/locale';
|
import { __ } from '~/locale';
|
||||||
import CollapsibleSidebar from './collapsible_sidebar.vue';
|
import CollapsibleSidebar from './collapsible_sidebar.vue';
|
||||||
import { rightSidebarViews } from '../../constants';
|
import { rightSidebarViews } from '../../constants';
|
||||||
import MergeRequestInfo from '../merge_requests/info.vue';
|
|
||||||
import PipelinesList from '../pipelines/list.vue';
|
import PipelinesList from '../pipelines/list.vue';
|
||||||
import JobsDetail from '../jobs/detail.vue';
|
import JobsDetail from '../jobs/detail.vue';
|
||||||
import Clientside from '../preview/clientside.vue';
|
import Clientside from '../preview/clientside.vue';
|
||||||
|
@ -28,12 +27,6 @@ export default {
|
||||||
},
|
},
|
||||||
rightExtensionTabs() {
|
rightExtensionTabs() {
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
show: Boolean(this.currentMergeRequestId),
|
|
||||||
title: __('Merge Request'),
|
|
||||||
views: [{ component: MergeRequestInfo, ...rightSidebarViews.mergeRequestInfo }],
|
|
||||||
icon: 'text-description',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
show: true,
|
show: true,
|
||||||
title: __('Pipelines'),
|
title: __('Pipelines'),
|
||||||
|
|
|
@ -44,9 +44,7 @@ export const getMergeRequestData = (
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
if (!state.projects[projectId].mergeRequests[mergeRequestId] || force) {
|
if (!state.projects[projectId].mergeRequests[mergeRequestId] || force) {
|
||||||
service
|
service
|
||||||
.getProjectMergeRequestData(targetProjectId || projectId, mergeRequestId, {
|
.getProjectMergeRequestData(targetProjectId || projectId, mergeRequestId)
|
||||||
render_html: true,
|
|
||||||
})
|
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
commit(types.SET_MERGE_REQUEST, {
|
commit(types.SET_MERGE_REQUEST, {
|
||||||
projectPath: projectId,
|
projectPath: projectId,
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Admin::LogsController < Admin::ApplicationController
|
||||||
|
|
||||||
def loggers
|
def loggers
|
||||||
@loggers ||= [
|
@loggers ||= [
|
||||||
Gitlab::AppLogger,
|
Gitlab::AppJsonLogger,
|
||||||
Gitlab::GitLogger,
|
Gitlab::GitLogger,
|
||||||
Gitlab::EnvironmentLogger,
|
Gitlab::EnvironmentLogger,
|
||||||
Gitlab::SidekiqLogger,
|
Gitlab::SidekiqLogger,
|
||||||
|
|
|
@ -8,6 +8,8 @@ class Projects::ServicesController < Projects::ApplicationController
|
||||||
before_action :ensure_service_enabled
|
before_action :ensure_service_enabled
|
||||||
before_action :service
|
before_action :service
|
||||||
before_action :web_hook_logs, only: [:edit, :update]
|
before_action :web_hook_logs, only: [:edit, :update]
|
||||||
|
before_action :set_deprecation_notice_for_prometheus_service, only: [:edit, :update]
|
||||||
|
before_action :redirect_deprecated_prometheus_service, only: [:update]
|
||||||
|
|
||||||
respond_to :html
|
respond_to :html
|
||||||
|
|
||||||
|
@ -93,4 +95,16 @@ class Projects::ServicesController < Projects::ApplicationController
|
||||||
.as_json(only: @service.json_fields)
|
.as_json(only: @service.json_fields)
|
||||||
.merge(errors: @service.errors.as_json)
|
.merge(errors: @service.errors.as_json)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def redirect_deprecated_prometheus_service
|
||||||
|
redirect_to edit_project_service_path(project, @service) if @service.is_a?(::PrometheusService) && Feature.enabled?(:settings_operations_prometheus_service, project)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_deprecation_notice_for_prometheus_service
|
||||||
|
return if !@service.is_a?(::PrometheusService) || !Feature.enabled?(:settings_operations_prometheus_service, project)
|
||||||
|
|
||||||
|
operations_link_start = "<a href=\"#{project_settings_operations_path(project)}\">"
|
||||||
|
message = s_('PrometheusService|You can now manage your Prometheus settings on the %{operations_link_start}Operations%{operations_link_end} page. Fields on this page has been deprecated.') % { operations_link_start: operations_link_start, operations_link_end: "</a>" }
|
||||||
|
flash.now[:alert] = message.html_safe
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ module AkismetMethods
|
||||||
@akismet ||= Spam::AkismetService.new(
|
@akismet ||= Spam::AkismetService.new(
|
||||||
spammable_owner.name,
|
spammable_owner.name,
|
||||||
spammable_owner.email,
|
spammable_owner.email,
|
||||||
spammable.spammable_text,
|
spammable.try(:spammable_text) || spammable&.text,
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,10 +11,14 @@ class IssuableBaseService < BaseService
|
||||||
@skip_milestone_email = @params.delete(:skip_milestone_email)
|
@skip_milestone_email = @params.delete(:skip_milestone_email)
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_params(issuable)
|
def can_admin_issuable?(issuable)
|
||||||
ability_name = :"admin_#{issuable.to_ability_name}"
|
ability_name = :"admin_#{issuable.to_ability_name}"
|
||||||
|
|
||||||
unless can?(current_user, ability_name, issuable)
|
can?(current_user, ability_name, issuable)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_params(issuable)
|
||||||
|
unless can_admin_issuable?(issuable)
|
||||||
params.delete(:milestone_id)
|
params.delete(:milestone_id)
|
||||||
params.delete(:labels)
|
params.delete(:labels)
|
||||||
params.delete(:add_label_ids)
|
params.delete(:add_label_ids)
|
||||||
|
|
|
@ -2,10 +2,17 @@
|
||||||
|
|
||||||
module Spam
|
module Spam
|
||||||
class HamService
|
class HamService
|
||||||
attr_accessor :spam_log
|
include AkismetMethods
|
||||||
|
|
||||||
|
attr_accessor :spam_log, :options
|
||||||
|
|
||||||
def initialize(spam_log)
|
def initialize(spam_log)
|
||||||
@spam_log = spam_log
|
@spam_log = spam_log
|
||||||
|
@user = spam_log.user
|
||||||
|
@options = {
|
||||||
|
ip_address: spam_log.source_ip,
|
||||||
|
user_agent: spam_log.user_agent
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
@ -16,17 +23,6 @@ module Spam
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
alias_method :spammable, :spam_log
|
||||||
|
|
||||||
def akismet
|
|
||||||
user = spam_log.user
|
|
||||||
@akismet ||= AkismetService.new(
|
|
||||||
user.name,
|
|
||||||
user.email,
|
|
||||||
spam_log.text,
|
|
||||||
ip_address: spam_log.source_ip,
|
|
||||||
user_agent: spam_log.user_agent
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
class StuckCiJobsWorker
|
class StuckCiJobsWorker
|
||||||
include ApplicationWorker
|
include ApplicationWorker
|
||||||
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
|
include CronjobQueue
|
||||||
|
|
||||||
feature_category :continuous_integration
|
feature_category :continuous_integration
|
||||||
worker_resource_boundary :cpu
|
worker_resource_boundary :cpu
|
||||||
|
@ -56,13 +56,13 @@ class StuckCiJobsWorker
|
||||||
loop do
|
loop do
|
||||||
jobs = Ci::Build.where(status: status)
|
jobs = Ci::Build.where(status: status)
|
||||||
.where(condition, timeout.ago)
|
.where(condition, timeout.ago)
|
||||||
.includes(:tags, :runner, project: :namespace)
|
.includes(:tags, :runner, project: [:namespace, :route])
|
||||||
.limit(100)
|
.limit(100)
|
||||||
.to_a
|
.to_a
|
||||||
break if jobs.empty?
|
break if jobs.empty?
|
||||||
|
|
||||||
jobs.each do |job|
|
jobs.each do |job|
|
||||||
yield(job)
|
with_context(project: job.project) { yield(job) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Move Merge Request from right sidebar of Web IDE to bottom bar
|
||||||
|
merge_request: 24746
|
||||||
|
author:
|
||||||
|
type: changed
|
5
changelogs/unreleased/ag-addjson-log-to-admin-logs.yml
Normal file
5
changelogs/unreleased/ag-addjson-log-to-admin-logs.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Replace unstructured application logs with structured (JSON) application logs in the admin interface
|
||||||
|
merge_request: 24614
|
||||||
|
author:
|
||||||
|
type: other
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Rename too long migration filename to address gem packaging limitations.
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: fixed
|
5
changelogs/unreleased/sh-promote-stackprof.yml
Normal file
5
changelogs/unreleased/sh-promote-stackprof.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Promote stackprof into a production gem
|
||||||
|
merge_request: 24564
|
||||||
|
author:
|
||||||
|
type: other
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DropActivatePrometheusServicesForSharedClusterApplicationsBackgroundMigration < ActiveRecord::Migration[5.2]
|
class DropBackgroundMigrationJobs < ActiveRecord::Migration[5.2]
|
||||||
include Gitlab::Database::MigrationHelpers
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
DOWNTIME = false
|
DOWNTIME = false
|
9
db/migrate/20200131181354_add_health_status_to_epics.rb
Normal file
9
db/migrate/20200131181354_add_health_status_to_epics.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddHealthStatusToEpics < ActiveRecord::Migration[6.0]
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
def change
|
||||||
|
add_column :epics, :health_status, :integer, limit: 2
|
||||||
|
end
|
||||||
|
end
|
9
db/migrate/20200131191754_add_health_status_to_issues.rb
Normal file
9
db/migrate/20200131191754_add_health_status_to_issues.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddHealthStatusToIssues < ActiveRecord::Migration[6.0]
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
def change
|
||||||
|
add_column :issues, :health_status, :integer, limit: 2
|
||||||
|
end
|
||||||
|
end
|
|
@ -1554,6 +1554,7 @@ ActiveRecord::Schema.define(version: 2020_02_07_151640) do
|
||||||
t.integer "state_id", limit: 2, default: 1, null: false
|
t.integer "state_id", limit: 2, default: 1, null: false
|
||||||
t.integer "start_date_sourcing_epic_id"
|
t.integer "start_date_sourcing_epic_id"
|
||||||
t.integer "due_date_sourcing_epic_id"
|
t.integer "due_date_sourcing_epic_id"
|
||||||
|
t.integer "health_status", limit: 2
|
||||||
t.index ["assignee_id"], name: "index_epics_on_assignee_id"
|
t.index ["assignee_id"], name: "index_epics_on_assignee_id"
|
||||||
t.index ["author_id"], name: "index_epics_on_author_id"
|
t.index ["author_id"], name: "index_epics_on_author_id"
|
||||||
t.index ["closed_by_id"], name: "index_epics_on_closed_by_id"
|
t.index ["closed_by_id"], name: "index_epics_on_closed_by_id"
|
||||||
|
@ -2181,6 +2182,7 @@ ActiveRecord::Schema.define(version: 2020_02_07_151640) do
|
||||||
t.integer "state_id", limit: 2, default: 1, null: false
|
t.integer "state_id", limit: 2, default: 1, null: false
|
||||||
t.integer "duplicated_to_id"
|
t.integer "duplicated_to_id"
|
||||||
t.integer "promoted_to_epic_id"
|
t.integer "promoted_to_epic_id"
|
||||||
|
t.integer "health_status", limit: 2
|
||||||
t.index ["author_id"], name: "index_issues_on_author_id"
|
t.index ["author_id"], name: "index_issues_on_author_id"
|
||||||
t.index ["closed_by_id"], name: "index_issues_on_closed_by_id"
|
t.index ["closed_by_id"], name: "index_issues_on_closed_by_id"
|
||||||
t.index ["confidential"], name: "index_issues_on_confidential"
|
t.index ["confidential"], name: "index_issues_on_confidential"
|
||||||
|
|
|
@ -24,7 +24,7 @@ module Gitlab
|
||||||
|
|
||||||
sum += method.self_time
|
sum += method.self_time
|
||||||
|
|
||||||
@output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%s\n" % [
|
@output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%-30s %s\n" % [
|
||||||
method.self_time / total_time * 100, # %self
|
method.self_time / total_time * 100, # %self
|
||||||
method.total_time, # total
|
method.total_time, # total
|
||||||
method.self_time, # self
|
method.self_time, # self
|
||||||
|
@ -32,7 +32,8 @@ module Gitlab
|
||||||
method.children_time, # children
|
method.children_time, # children
|
||||||
method.called, # calls
|
method.called, # calls
|
||||||
method.recursive? ? "*" : " ", # cycle
|
method.recursive? ? "*" : " ", # cycle
|
||||||
method_name(method) # name
|
method.full_name, # method_name
|
||||||
|
method_location(method) # location
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15235,6 +15235,9 @@ msgstr ""
|
||||||
msgid "PrometheusService|Waiting for your first deployment to an environment to find common metrics"
|
msgid "PrometheusService|Waiting for your first deployment to an environment to find common metrics"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "PrometheusService|You can now manage your Prometheus settings on the %{operations_link_start}Operations%{operations_link_end} page. Fields on this page has been deprecated."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Promote"
|
msgid "Promote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -21435,6 +21438,9 @@ msgstr ""
|
||||||
msgid "Web terminal"
|
msgid "Web terminal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "WebIDE|Merge request"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Webhooks"
|
msgid "Webhooks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module QA
|
module QA
|
||||||
context 'Plan', :reliable do
|
context 'Plan' do
|
||||||
describe 'Close issue' do
|
describe 'Close issue' do
|
||||||
let(:issue) do
|
let(:issue) do
|
||||||
Resource::Issue.fabricate_via_api!
|
Resource::Issue.fabricate_via_api!
|
||||||
|
|
|
@ -191,16 +191,81 @@ describe Projects::ServicesController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'Prometheus service' do
|
||||||
|
let!(:service) { create(:prometheus_service, project: project) }
|
||||||
|
let(:service_params) { { manual_configuration: '1', api_url: 'http://example.com' } }
|
||||||
|
|
||||||
|
context 'feature flag :settings_operations_prometheus_service is enabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(settings_operations_prometheus_service: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects user back to edit page with alert' do
|
||||||
|
put :update, params: project_params.merge(service: service_params)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(edit_project_service_path(project, service))
|
||||||
|
expected_alert = "You can now manage your Prometheus settings on the <a href=\"#{project_settings_operations_path(project)}\">Operations</a> page. Fields on this page has been deprecated."
|
||||||
|
|
||||||
|
expect(response).to set_flash.now[:alert].to(expected_alert)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not modify service' do
|
||||||
|
expect { put :update, params: project_params.merge(service: service_params) }.not_to change { project.prometheus_service.reload.attributes }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'feature flag :settings_operations_prometheus_service is disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(settings_operations_prometheus_service: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'modifies service' do
|
||||||
|
expect { put :update, params: project_params.merge(service: service_params) }.to change { project.prometheus_service.reload.attributes }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #edit' do
|
describe 'GET #edit' do
|
||||||
before do
|
context 'Jira service' do
|
||||||
get :edit, params: project_params(id: 'jira')
|
let(:service_param) { 'jira' }
|
||||||
|
|
||||||
|
before do
|
||||||
|
get :edit, params: project_params(id: service_param)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with approved services' do
|
||||||
|
it 'renders edit page' do
|
||||||
|
expect(response).to be_successful
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with approved services' do
|
context 'Prometheus service' do
|
||||||
it 'renders edit page' do
|
let(:service_param) { 'prometheus' }
|
||||||
expect(response).to be_successful
|
|
||||||
|
context 'feature flag :settings_operations_prometheus_service is enabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(settings_operations_prometheus_service: true)
|
||||||
|
get :edit, params: project_params(id: service_param)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders deprecation warning notice' do
|
||||||
|
expected_alert = "You can now manage your Prometheus settings on the <a href=\"#{project_settings_operations_path(project)}\">Operations</a> page. Fields on this page has been deprecated."
|
||||||
|
expect(response).to set_flash.now[:alert].to(expected_alert)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'feature flag :settings_operations_prometheus_service is disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(settings_operations_prometheus_service: false)
|
||||||
|
get :edit, params: project_params(id: service_param)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not render deprecation warning notice' do
|
||||||
|
expect(response).not_to set_flash.now[:alert]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,7 +10,7 @@ describe 'Admin browses logs' do
|
||||||
it 'shows available log files' do
|
it 'shows available log files' do
|
||||||
visit admin_logs_path
|
visit admin_logs_path
|
||||||
|
|
||||||
expect(page).to have_link 'application.log'
|
expect(page).to have_link 'application_json.log'
|
||||||
expect(page).to have_link 'git_json.log'
|
expect(page).to have_link 'git_json.log'
|
||||||
expect(page).to have_link 'test.log'
|
expect(page).to have_link 'test.log'
|
||||||
expect(page).to have_link 'sidekiq.log'
|
expect(page).to have_link 'sidekiq.log'
|
||||||
|
|
|
@ -15,11 +15,12 @@ describe 'User activates Prometheus' do
|
||||||
click_link('Prometheus')
|
click_link('Prometheus')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'activates service' do
|
it 'does not activate service and informs about deprecation' do
|
||||||
check('Active')
|
check('Active')
|
||||||
fill_in('API URL', with: 'http://prometheus.example.com')
|
fill_in('API URL', with: 'http://prometheus.example.com')
|
||||||
click_button('Save changes')
|
click_button('Save changes')
|
||||||
|
|
||||||
expect(page).to have_content('Prometheus activated.')
|
expect(page).not_to have_content('Prometheus activated.')
|
||||||
|
expect(page).to have_content('Fields on this page has been deprecated.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
59
spec/frontend/ide/components/ide_status_mr_spec.js
Normal file
59
spec/frontend/ide/components/ide_status_mr_spec.js
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { GlIcon, GlLink } from '@gitlab/ui';
|
||||||
|
import { TEST_HOST } from 'helpers/test_constants';
|
||||||
|
import IdeStatusMr from '~/ide/components/ide_status_mr.vue';
|
||||||
|
|
||||||
|
const TEST_TEXT = '!9001';
|
||||||
|
const TEST_URL = `${TEST_HOST}merge-requests/9001`;
|
||||||
|
|
||||||
|
describe('ide/components/ide_status_mr', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
const createComponent = props => {
|
||||||
|
wrapper = shallowMount(IdeStatusMr, {
|
||||||
|
propsData: props,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const findIcon = () => wrapper.find(GlIcon);
|
||||||
|
const findLink = () => wrapper.find(GlLink);
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when mounted', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
createComponent({
|
||||||
|
text: TEST_TEXT,
|
||||||
|
url: TEST_URL,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders icon', () => {
|
||||||
|
const icon = findIcon();
|
||||||
|
|
||||||
|
expect(icon.exists()).toBe(true);
|
||||||
|
expect(icon.props()).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
name: 'merge-request',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders link', () => {
|
||||||
|
const link = findLink();
|
||||||
|
|
||||||
|
expect(link.exists()).toBe(true);
|
||||||
|
expect(link.attributes()).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
href: TEST_URL,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(link.text()).toEqual(TEST_TEXT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text', () => {
|
||||||
|
expect(wrapper.text()).toBe(`Merge request ${TEST_TEXT}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -75,28 +75,6 @@ describe('ide/components/panes/right.vue', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('merge request tab', () => {
|
|
||||||
it('is shown if there is a currentMergeRequestId', () => {
|
|
||||||
store.state.currentMergeRequestId = 1;
|
|
||||||
|
|
||||||
createComponent();
|
|
||||||
|
|
||||||
expect(wrapper.find(CollapsibleSidebar).props('extensionTabs')).toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
show: true,
|
|
||||||
title: 'Merge Request',
|
|
||||||
views: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
name: rightSidebarViews.mergeRequestInfo.name,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('clientside live preview tab', () => {
|
describe('clientside live preview tab', () => {
|
||||||
it('is shown if there is a packageJson and clientsidePreviewEnabled', () => {
|
it('is shown if there is a packageJson and clientsidePreviewEnabled', () => {
|
||||||
Vue.set(store.state.entries, 'package.json', {
|
Vue.set(store.state.entries, 'package.json', {
|
||||||
|
|
|
@ -1,94 +1,129 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import _ from 'lodash';
|
||||||
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
||||||
import store from '~/ide/stores';
|
import { TEST_HOST } from 'spec/test_constants';
|
||||||
import ideStatusBar from '~/ide/components/ide_status_bar.vue';
|
import { createStore } from '~/ide/stores';
|
||||||
|
import IdeStatusBar from '~/ide/components/ide_status_bar.vue';
|
||||||
import { rightSidebarViews } from '~/ide/constants';
|
import { rightSidebarViews } from '~/ide/constants';
|
||||||
import { resetStore } from '../helpers';
|
|
||||||
import { projectData } from '../mock_data';
|
import { projectData } from '../mock_data';
|
||||||
|
|
||||||
|
const TEST_PROJECT_ID = 'abcproject';
|
||||||
|
const TEST_MERGE_REQUEST_ID = '9001';
|
||||||
|
const TEST_MERGE_REQUEST_URL = `${TEST_HOST}merge-requests/${TEST_MERGE_REQUEST_ID}`;
|
||||||
|
|
||||||
describe('ideStatusBar', () => {
|
describe('ideStatusBar', () => {
|
||||||
|
let store;
|
||||||
let vm;
|
let vm;
|
||||||
|
|
||||||
|
const createComponent = () => {
|
||||||
|
vm = createComponentWithStore(Vue.extend(IdeStatusBar), store).$mount();
|
||||||
|
};
|
||||||
|
const findMRStatus = () => vm.$el.querySelector('.js-ide-status-mr');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const Component = Vue.extend(ideStatusBar);
|
store = createStore();
|
||||||
|
store.state.currentProjectId = TEST_PROJECT_ID;
|
||||||
store.state.currentProjectId = 'abcproject';
|
store.state.projects[TEST_PROJECT_ID] = _.clone(projectData);
|
||||||
store.state.projects.abcproject = projectData;
|
|
||||||
store.state.currentBranchId = 'master';
|
store.state.currentBranchId = 'master';
|
||||||
|
|
||||||
vm = createComponentWithStore(Component, store).$mount();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vm.$destroy();
|
vm.$destroy();
|
||||||
|
|
||||||
resetStore(vm.$store);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the statusbar', () => {
|
describe('default', () => {
|
||||||
expect(vm.$el.className).toBe('ide-status-bar');
|
beforeEach(() => {
|
||||||
});
|
createComponent();
|
||||||
|
});
|
||||||
|
|
||||||
describe('mounted', () => {
|
|
||||||
it('triggers a setInterval', () => {
|
it('triggers a setInterval', () => {
|
||||||
expect(vm.intervalId).not.toBe(null);
|
expect(vm.intervalId).not.toBe(null);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('commitAgeUpdate', () => {
|
it('renders the statusbar', () => {
|
||||||
beforeEach(function() {
|
expect(vm.$el.className).toBe('ide-status-bar');
|
||||||
jasmine.clock().install();
|
|
||||||
spyOn(vm, 'commitAgeUpdate').and.callFake(() => {});
|
|
||||||
vm.startTimer();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
describe('commitAgeUpdate', () => {
|
||||||
jasmine.clock().uninstall();
|
beforeEach(function() {
|
||||||
});
|
jasmine.clock().install();
|
||||||
|
spyOn(vm, 'commitAgeUpdate').and.callFake(() => {});
|
||||||
it('gets called every second', () => {
|
vm.startTimer();
|
||||||
expect(vm.commitAgeUpdate).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
jasmine.clock().tick(1100);
|
|
||||||
|
|
||||||
expect(vm.commitAgeUpdate.calls.count()).toEqual(1);
|
|
||||||
|
|
||||||
jasmine.clock().tick(1000);
|
|
||||||
|
|
||||||
expect(vm.commitAgeUpdate.calls.count()).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getCommitPath', () => {
|
|
||||||
it('returns the path to the commit details', () => {
|
|
||||||
expect(vm.getCommitPath('abc123de')).toBe('/commit/abc123de');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pipeline status', () => {
|
|
||||||
it('opens right sidebar on clicking icon', done => {
|
|
||||||
spyOn(vm, 'openRightPane');
|
|
||||||
Vue.set(vm.$store.state.pipelines, 'latestPipeline', {
|
|
||||||
details: {
|
|
||||||
status: {
|
|
||||||
text: 'success',
|
|
||||||
details_path: 'test',
|
|
||||||
icon: 'status_success',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
commit: {
|
|
||||||
author_gravatar_url: 'www',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
vm.$nextTick()
|
afterEach(function() {
|
||||||
.then(() => {
|
jasmine.clock().uninstall();
|
||||||
vm.$el.querySelector('.ide-status-pipeline button').click();
|
});
|
||||||
|
|
||||||
expect(vm.openRightPane).toHaveBeenCalledWith(rightSidebarViews.pipelines);
|
it('gets called every second', () => {
|
||||||
})
|
expect(vm.commitAgeUpdate).not.toHaveBeenCalled();
|
||||||
.then(done)
|
|
||||||
.catch(done.fail);
|
jasmine.clock().tick(1100);
|
||||||
|
|
||||||
|
expect(vm.commitAgeUpdate.calls.count()).toEqual(1);
|
||||||
|
|
||||||
|
jasmine.clock().tick(1000);
|
||||||
|
|
||||||
|
expect(vm.commitAgeUpdate.calls.count()).toEqual(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getCommitPath', () => {
|
||||||
|
it('returns the path to the commit details', () => {
|
||||||
|
expect(vm.getCommitPath('abc123de')).toBe('/commit/abc123de');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pipeline status', () => {
|
||||||
|
it('opens right sidebar on clicking icon', done => {
|
||||||
|
spyOn(vm, 'openRightPane');
|
||||||
|
Vue.set(vm.$store.state.pipelines, 'latestPipeline', {
|
||||||
|
details: {
|
||||||
|
status: {
|
||||||
|
text: 'success',
|
||||||
|
details_path: 'test',
|
||||||
|
icon: 'status_success',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
commit: {
|
||||||
|
author_gravatar_url: 'www',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.$nextTick()
|
||||||
|
.then(() => {
|
||||||
|
vm.$el.querySelector('.ide-status-pipeline button').click();
|
||||||
|
|
||||||
|
expect(vm.openRightPane).toHaveBeenCalledWith(rightSidebarViews.pipelines);
|
||||||
|
})
|
||||||
|
.then(done)
|
||||||
|
.catch(done.fail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not show merge request status', () => {
|
||||||
|
expect(findMRStatus()).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with merge request in store', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
store.state.projects[TEST_PROJECT_ID].mergeRequests = {
|
||||||
|
[TEST_MERGE_REQUEST_ID]: {
|
||||||
|
web_url: TEST_MERGE_REQUEST_URL,
|
||||||
|
references: {
|
||||||
|
short: `!${TEST_MERGE_REQUEST_ID}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
store.state.currentMergeRequestId = TEST_MERGE_REQUEST_ID;
|
||||||
|
|
||||||
|
createComponent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows merge request status', () => {
|
||||||
|
expect(findMRStatus().textContent.trim()).toEqual(`Merge request !${TEST_MERGE_REQUEST_ID}`);
|
||||||
|
expect(findMRStatus().querySelector('a').href).toEqual(TEST_MERGE_REQUEST_URL);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
import Vue from 'vue';
|
|
||||||
import '~/behaviors/markdown/render_gfm';
|
|
||||||
import { createStore } from '~/ide/stores';
|
|
||||||
import Info from '~/ide/components/merge_requests/info.vue';
|
|
||||||
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
|
|
||||||
|
|
||||||
describe('IDE merge request details', () => {
|
|
||||||
let Component;
|
|
||||||
let vm;
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
Component = Vue.extend(Info);
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
const store = createStore();
|
|
||||||
store.state.currentProjectId = 'gitlab-ce';
|
|
||||||
store.state.currentMergeRequestId = 1;
|
|
||||||
store.state.projects['gitlab-ce'] = {
|
|
||||||
mergeRequests: {
|
|
||||||
1: {
|
|
||||||
iid: 1,
|
|
||||||
title: 'Testing',
|
|
||||||
title_html: '<span class="title-html">Testing</span>',
|
|
||||||
description: 'Description',
|
|
||||||
description_html: '<p class="description-html">Description HTML</p>',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
vm = createComponentWithStore(Component, store).$mount();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
vm.$destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders merge request IID', () => {
|
|
||||||
expect(vm.$el.querySelector('.detail-page-header').textContent).toContain('!1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders title as HTML', () => {
|
|
||||||
expect(vm.$el.querySelector('.title-html')).not.toBe(null);
|
|
||||||
expect(vm.$el.querySelector('.title').textContent).toContain('Testing');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders description as HTML', () => {
|
|
||||||
expect(vm.$el.querySelector('.description-html')).not.toBe(null);
|
|
||||||
expect(vm.$el.querySelector('.description').textContent).toContain('Description HTML');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -137,9 +137,7 @@ describe('IDE store merge request actions', () => {
|
||||||
store
|
store
|
||||||
.dispatch('getMergeRequestData', { projectId: TEST_PROJECT, mergeRequestId: 1 })
|
.dispatch('getMergeRequestData', { projectId: TEST_PROJECT, mergeRequestId: 1 })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
expect(service.getProjectMergeRequestData).toHaveBeenCalledWith(TEST_PROJECT, 1, {
|
expect(service.getProjectMergeRequestData).toHaveBeenCalledWith(TEST_PROJECT, 1);
|
||||||
render_html: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,6 +30,7 @@ Issue:
|
||||||
- last_edited_at
|
- last_edited_at
|
||||||
- last_edited_by_id
|
- last_edited_by_id
|
||||||
- discussion_locked
|
- discussion_locked
|
||||||
|
- health_status
|
||||||
Event:
|
Event:
|
||||||
- id
|
- id
|
||||||
- target_type
|
- target_type
|
||||||
|
@ -824,3 +825,4 @@ Epic:
|
||||||
- state_id
|
- state_id
|
||||||
- start_date_sourcing_epic_id
|
- start_date_sourcing_epic_id
|
||||||
- due_date_sourcing_epic_id
|
- due_date_sourcing_epic_id
|
||||||
|
- health_status
|
||||||
|
|
|
@ -192,4 +192,43 @@ describe Gitlab::Profiler do
|
||||||
expect(described_class.log_load_times_by_model(null_logger)).to be_nil
|
expect(described_class.log_load_times_by_model(null_logger)).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.print_by_total_time' do
|
||||||
|
let(:stdout) { StringIO.new }
|
||||||
|
|
||||||
|
let(:output) do
|
||||||
|
stdout.rewind
|
||||||
|
stdout.read
|
||||||
|
end
|
||||||
|
|
||||||
|
let_it_be(:result) do
|
||||||
|
RubyProf.profile do
|
||||||
|
sleep 0.1
|
||||||
|
1.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_const('STDOUT', stdout)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'prints a profile result sorted by total time' do
|
||||||
|
described_class.print_by_total_time(result)
|
||||||
|
|
||||||
|
total_times =
|
||||||
|
output
|
||||||
|
.scan(/^\s+\d+\.\d+\s+(\d+\.\d+)/)
|
||||||
|
.map { |(total)| total.to_f }
|
||||||
|
|
||||||
|
expect(output).to include('Kernel#sleep')
|
||||||
|
expect(total_times).to eq(total_times.sort.reverse)
|
||||||
|
expect(total_times).not_to eq(total_times.uniq)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'accepts a max_percent option' do
|
||||||
|
described_class.print_by_total_time(result, max_percent: 50)
|
||||||
|
|
||||||
|
expect(output).not_to include('Kernel#sleep')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require Rails.root.join('db', 'migrate', '20200116051619_drop_activate_prometheus_services_for_shared_cluster_applications_background_migration.rb')
|
require Rails.root.join('db', 'migrate', '20200116051619_drop_background_migration_jobs.rb')
|
||||||
|
|
||||||
describe DropActivatePrometheusServicesForSharedClusterApplicationsBackgroundMigration, :sidekiq, :redis, :migration, schema: 2020_01_16_051619 do
|
describe DropBackgroundMigrationJobs, :sidekiq, :redis, :migration, schema: 2020_01_16_051619 do
|
||||||
subject(:migration) { described_class.new }
|
subject(:migration) { described_class.new }
|
||||||
|
|
||||||
describe '#up' do
|
describe '#up' do
|
|
@ -72,4 +72,4 @@ DEPENDENCIES
|
||||||
scss_lint (~> 0.56.0)
|
scss_lint (~> 0.56.0)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.1.2
|
1.17.3
|
||||||
|
|
Loading…
Reference in a new issue