Commit c57e10fa authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 11e5d1b9
...@@ -381,8 +381,6 @@ group :development, :test do ...@@ -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' ...@@ -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 ...@@ -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 ...@@ -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 @@ ...@@ -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 { ...@@ -15,6 +16,7 @@ export default {
userAvatarImage, userAvatarImage,
CiIcon, CiIcon,
IdeStatusList, IdeStatusList,
IdeStatusMr,
}, },
directives: { directives: {
tooltip, tooltip,
...@@ -27,7 +29,7 @@ export default { ...@@ -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 { ...@@ -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>
<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>
<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'; ...@@ -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 { ...@@ -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 = ( ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 @@ ...@@ -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 ...@@ -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 @@ ...@@ -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 ...@@ -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
......
---
title: Move Merge Request from right sidebar of Web IDE to bottom bar
merge_request: 24746
author:
type: changed
---
title: Replace unstructured application logs with structured (JSON) application logs in the admin interface
merge_request: 24614
author:
type: other
---
title: Rename too long migration filename to address gem packaging limitations.
merge_request:
author:
type: fixed
---
title: Promote stackprof into a production gem
merge_request: 24564
author:
type: other
# 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
......
# frozen_string_literal: true
class AddHealthStatusToEpics < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :epics, :health_status, :integer, limit: 2
end
end
# 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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 "" ...@@ -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 "" ...@@ -21435,6 +21438,9 @@ msgstr ""
msgid "Web terminal" msgid "Web terminal"
msgstr "" msgstr ""
msgid "WebIDE|Merge request"
msgstr ""
msgid "Webhooks" msgid "Webhooks"
msgstr "" msgstr ""
......
# 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 ...@@ -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 ...@@ -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 ...@@ -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
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', () => { ...@@ -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', {
......
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;
beforeEach(() => { const createComponent = () => {
const Component = Vue.extend(ideStatusBar); vm = createComponentWithStore(Vue.extend(IdeStatusBar), store).$mount();
};
const findMRStatus = () => vm.$el.querySelector('.js-ide-status-mr');
store.state.currentProjectId = 'abcproject'; beforeEach(() => {
store.state.projects.abcproject = projectData; store = createStore();
store.state.currentProjectId = TEST_PROJECT_ID;
store.state.projects[TEST_PROJECT_ID] = _.clone(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(() => {});
vm.startTimer();
});
it('gets called every second', () => { afterEach(function() {
expect(vm.commitAgeUpdate).not.toHaveBeenCalled(); jasmine.clock().uninstall();
});
jasmine.clock().tick(1100); it('gets called every second', () => {
expect(vm.commitAgeUpdate).not.toHaveBeenCalled();
expect(vm.commitAgeUpdate.calls.count()).toEqual(1); jasmine.clock().tick(1100);
jasmine.clock().tick(1000); expect(vm.commitAgeUpdate.calls.count()).toEqual(1);
expect(vm.commitAgeUpdate.calls.count()).toEqual(2); jasmine.clock().tick(1000);
expect(vm.commitAgeUpdate.calls.count()).toEqual(2);
});
}); });
});
describe('getCommitPath', () => { describe('getCommitPath', () => {
it('returns the path to the commit details', () => { it('returns the path to the commit details', () => {
expect(vm.getCommitPath('abc123de')).toBe('/commit/abc123de'); 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('pipeline status', () => { describe('with merge request in store', () => {
it('opens right sidebar on clicking icon', done => { beforeEach(() => {
spyOn(vm, 'openRightPane'); store.state.projects[TEST_PROJECT_ID].mergeRequests = {
Vue.set(vm.$store.state.pipelines, 'latestPipeline', { [TEST_MERGE_REQUEST_ID]: {
details: { web_url: TEST_MERGE_REQUEST_URL,
status: { references: {
text: 'success', short: `!${TEST_MERGE_REQUEST_ID}`,
details_path: 'test',
icon: 'status_success',
}, },
}, },
commit: { };
author_gravatar_url: 'www', store.state.currentMergeRequestId = TEST_MERGE_REQUEST_ID;
},
});
vm.$nextTick() createComponent();
.then(() => { });
vm.$el.querySelector('.ide-status-pipeline button').click();
expect(vm.openRightPane).toHaveBeenCalledWith(rightSidebarViews.pipelines); it('shows merge request status', () => {
}) expect(findMRStatus().textContent.trim()).toEqual(`Merge request !${TEST_MERGE_REQUEST_ID}`);
.then(done) expect(findMRStatus().querySelector('a').href).toEqual(TEST_MERGE_REQUEST_URL);
.catch(done.fail);
}); });
}); });
}); });
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', () => { ...@@ -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: ...@@ -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: ...@@ -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 ...@@ -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
# 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 ...@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment