Browse Source

Add latest changes from gitlab-org/gitlab@master

tags/v12.9.0.pre
GitLab Bot 1 month ago
parent
commit
c57e10faab
36 changed files with 393 additions and 218 deletions
  1. +1
    -2
      Gemfile
  2. +2
    -2
      Gemfile.lock
  3. +9
    -1
      app/assets/javascripts/ide/components/ide_status_bar.vue
  4. +28
    -0
      app/assets/javascripts/ide/components/ide_status_mr.vue
  5. +0
    -38
      app/assets/javascripts/ide/components/merge_requests/info.vue
  6. +0
    -7
      app/assets/javascripts/ide/components/panes/right.vue
  7. +1
    -3
      app/assets/javascripts/ide/stores/actions/merge_request.js
  8. +1
    -1
      app/controllers/admin/logs_controller.rb
  9. +14
    -0
      app/controllers/projects/services_controller.rb
  10. +1
    -1
      app/services/concerns/akismet_methods.rb
  11. +6
    -2
      app/services/issuable_base_service.rb
  12. +9
    -13
      app/services/spam/ham_service.rb
  13. +3
    -3
      app/workers/stuck_ci_jobs_worker.rb
  14. +5
    -0
      changelogs/unreleased/196070-move-mr-from-right-sidebar-to-bottom-bar.yml
  15. +5
    -0
      changelogs/unreleased/ag-addjson-log-to-admin-logs.yml
  16. +5
    -0
      changelogs/unreleased/mwaw-rename_to_long_migration_filename.yml
  17. +5
    -0
      changelogs/unreleased/sh-promote-stackprof.yml
  18. +1
    -1
      db/migrate/20200116051619_drop_background_migration_jobs.rb
  19. +9
    -0
      db/migrate/20200131181354_add_health_status_to_epics.rb
  20. +9
    -0
      db/migrate/20200131191754_add_health_status_to_issues.rb
  21. +2
    -0
      db/schema.rb
  22. +3
    -2
      lib/gitlab/profiler/total_time_flat_printer.rb
  23. +6
    -0
      locale/gitlab.pot
  24. +1
    -1
      qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb
  25. +70
    -5
      spec/controllers/projects/services_controller_spec.rb
  26. +1
    -1
      spec/features/admin/admin_browses_logs_spec.rb
  27. +3
    -2
      spec/features/projects/services/user_activates_prometheus_spec.rb
  28. +59
    -0
      spec/frontend/ide/components/ide_status_mr_spec.js
  29. +0
    -22
      spec/frontend/ide/components/panes/right_spec.js
  30. +89
    -54
      spec/javascripts/ide/components/ide_status_bar_spec.js
  31. +0
    -51
      spec/javascripts/ide/components/merge_requests/info_spec.js
  32. +1
    -3
      spec/javascripts/ide/stores/actions/merge_request_spec.js
  33. +2
    -0
      spec/lib/gitlab/import_export/safe_model_attributes.yml
  34. +39
    -0
      spec/lib/gitlab/profiler_spec.rb
  35. +2
    -2
      spec/migrations/drop_background_migration_jobs_spec.rb
  36. +1
    -1
      tooling/overcommit/gems.locked

+ 1
- 2
Gemfile View File

@@ -381,8 +381,6 @@ group :development, :test do

gem 'knapsack', '~> 1.17'

gem 'stackprof', '~> 0.2.13', require: false

gem 'simple_po_parser', '~> 1.1.2', require: false

gem 'timecop', '~> 0.8.0'
@@ -427,6 +425,7 @@ gem 'email_reply_trimmer', '~> 0.1'
gem 'html2text'

gem 'ruby-prof', '~> 1.0.0'
gem 'stackprof', '~> 0.2.15', require: false
gem 'rbtrace', '~> 0.4', require: false
gem 'memory_profiler', '~> 0.9', require: false
gem 'benchmark-memory', '~> 0.1', require: false


+ 2
- 2
Gemfile.lock View File

@@ -1037,7 +1037,7 @@ GEM
sprockets (>= 3.0.0)
sqlite3 (1.3.13)
sshkey (2.0.0)
stackprof (0.2.13)
stackprof (0.2.15)
state_machines (0.5.0)
state_machines-activemodel (0.7.1)
activemodel (>= 4.1)
@@ -1382,7 +1382,7 @@ DEPENDENCIES
spring-commands-rspec (~> 1.0.4)
sprockets (~> 3.7.0)
sshkey (~> 2.0)
stackprof (~> 0.2.13)
stackprof (~> 0.2.15)
state_machines-activerecord (~> 0.6.0)
sys-filesystem (~> 1.1.6)
test-prof (~> 0.10.0)


+ 9
- 1
app/assets/javascripts/ide/components/ide_status_bar.vue View File

@@ -2,6 +2,7 @@
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { mapActions, mapState, mapGetters } from 'vuex';
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 tooltip from '~/vue_shared/directives/tooltip';
import timeAgoMixin from '~/vue_shared/mixins/timeago';
@@ -15,6 +16,7 @@ export default {
userAvatarImage,
CiIcon,
IdeStatusList,
IdeStatusMr,
},
directives: {
tooltip,
@@ -27,7 +29,7 @@ export default {
},
computed: {
...mapState(['currentBranchId', 'currentProjectId']),
...mapGetters(['currentProject', 'lastCommit']),
...mapGetters(['currentProject', 'lastCommit', 'currentMergeRequest']),
...mapState('pipelines', ['latestPipeline']),
},
watch: {
@@ -121,6 +123,12 @@ export default {
>{{ lastCommitFormattedAge }}</time
>
</div>
<ide-status-mr
v-if="currentMergeRequest"
class="mx-3"
:url="currentMergeRequest.web_url"
:text="currentMergeRequest.references.short"
/>
<ide-status-list class="ml-auto" />
</footer>
</template>

+ 28
- 0
app/assets/javascripts/ide/components/ide_status_mr.vue View 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>

+ 0
- 38
app/assets/javascripts/ide/components/merge_requests/info.vue View File

@@ -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>

+ 0
- 7
app/assets/javascripts/ide/components/panes/right.vue View File

@@ -3,7 +3,6 @@ import { mapGetters, mapState } from 'vuex';
import { __ } from '~/locale';
import CollapsibleSidebar from './collapsible_sidebar.vue';
import { rightSidebarViews } from '../../constants';
import MergeRequestInfo from '../merge_requests/info.vue';
import PipelinesList from '../pipelines/list.vue';
import JobsDetail from '../jobs/detail.vue';
import Clientside from '../preview/clientside.vue';
@@ -28,12 +27,6 @@ export default {
},
rightExtensionTabs() {
return [
{
show: Boolean(this.currentMergeRequestId),
title: __('Merge Request'),
views: [{ component: MergeRequestInfo, ...rightSidebarViews.mergeRequestInfo }],
icon: 'text-description',
},
{
show: true,
title: __('Pipelines'),


+ 1
- 3
app/assets/javascripts/ide/stores/actions/merge_request.js View File

@@ -44,9 +44,7 @@ export const getMergeRequestData = (
new Promise((resolve, reject) => {
if (!state.projects[projectId].mergeRequests[mergeRequestId] || force) {
service
.getProjectMergeRequestData(targetProjectId || projectId, mergeRequestId, {
render_html: true,
})
.getProjectMergeRequestData(targetProjectId || projectId, mergeRequestId)
.then(({ data }) => {
commit(types.SET_MERGE_REQUEST, {
projectPath: projectId,


+ 1
- 1
app/controllers/admin/logs_controller.rb View File

@@ -10,7 +10,7 @@ class Admin::LogsController < Admin::ApplicationController

def loggers
@loggers ||= [
Gitlab::AppLogger,
Gitlab::AppJsonLogger,
Gitlab::GitLogger,
Gitlab::EnvironmentLogger,
Gitlab::SidekiqLogger,


+ 14
- 0
app/controllers/projects/services_controller.rb View File

@@ -8,6 +8,8 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :ensure_service_enabled
before_action :service
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

@@ -93,4 +95,16 @@ class Projects::ServicesController < Projects::ApplicationController
.as_json(only: @service.json_fields)
.merge(errors: @service.errors.as_json)
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

+ 1
- 1
app/services/concerns/akismet_methods.rb View File

@@ -9,7 +9,7 @@ module AkismetMethods
@akismet ||= Spam::AkismetService.new(
spammable_owner.name,
spammable_owner.email,
spammable.spammable_text,
spammable.try(:spammable_text) || spammable&.text,
options
)
end


+ 6
- 2
app/services/issuable_base_service.rb View File

@@ -11,10 +11,14 @@ class IssuableBaseService < BaseService
@skip_milestone_email = @params.delete(:skip_milestone_email)
end

def filter_params(issuable)
def can_admin_issuable?(issuable)
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(:labels)
params.delete(:add_label_ids)


+ 9
- 13
app/services/spam/ham_service.rb View File

@@ -2,10 +2,17 @@

module Spam
class HamService
attr_accessor :spam_log
include AkismetMethods

attr_accessor :spam_log, :options

def initialize(spam_log)
@spam_log = spam_log
@user = spam_log.user
@options = {
ip_address: spam_log.source_ip,
user_agent: spam_log.user_agent
}
end

def execute
@@ -16,17 +23,6 @@ module Spam
end
end

private

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
alias_method :spammable, :spam_log
end
end

+ 3
- 3
app/workers/stuck_ci_jobs_worker.rb View File

@@ -2,7 +2,7 @@

class StuckCiJobsWorker
include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
include CronjobQueue

feature_category :continuous_integration
worker_resource_boundary :cpu
@@ -56,13 +56,13 @@ class StuckCiJobsWorker
loop do
jobs = Ci::Build.where(status: status)
.where(condition, timeout.ago)
.includes(:tags, :runner, project: :namespace)
.includes(:tags, :runner, project: [:namespace, :route])
.limit(100)
.to_a
break if jobs.empty?

jobs.each do |job|
yield(job)
with_context(project: job.project) { yield(job) }
end
end
end


+ 5
- 0
changelogs/unreleased/196070-move-mr-from-right-sidebar-to-bottom-bar.yml View File

@@ -0,0 +1,5 @@
---
title: Move Merge Request from right sidebar of Web IDE to bottom bar
merge_request: 24746
author:
type: changed

+ 5
- 0
changelogs/unreleased/ag-addjson-log-to-admin-logs.yml View 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

+ 5
- 0
changelogs/unreleased/mwaw-rename_to_long_migration_filename.yml View File

@@ -0,0 +1,5 @@
---
title: Rename too long migration filename to address gem packaging limitations.
merge_request:
author:
type: fixed

+ 5
- 0
changelogs/unreleased/sh-promote-stackprof.yml View File

@@ -0,0 +1,5 @@
---
title: Promote stackprof into a production gem
merge_request: 24564
author:
type: other

db/migrate/20200116051619_drop_activate_prometheus_services_for_shared_cluster_applications_background_migration.rb → db/migrate/20200116051619_drop_background_migration_jobs.rb View File

@@ -1,6 +1,6 @@
# frozen_string_literal: true

class DropActivatePrometheusServicesForSharedClusterApplicationsBackgroundMigration < ActiveRecord::Migration[5.2]
class DropBackgroundMigrationJobs < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers

DOWNTIME = false

+ 9
- 0
db/migrate/20200131181354_add_health_status_to_epics.rb View 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
- 0
db/migrate/20200131191754_add_health_status_to_issues.rb View 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

+ 2
- 0
db/schema.rb View File

@@ -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 "start_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 ["author_id"], name: "index_epics_on_author_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 "duplicated_to_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 ["closed_by_id"], name: "index_issues_on_closed_by_id"
t.index ["confidential"], name: "index_issues_on_confidential"


+ 3
- 2
lib/gitlab/profiler/total_time_flat_printer.rb View File

@@ -24,7 +24,7 @@ module Gitlab

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.total_time, # total
method.self_time, # self
@@ -32,7 +32,8 @@ module Gitlab
method.children_time, # children
method.called, # calls
method.recursive? ? "*" : " ", # cycle
method_name(method) # name
method.full_name, # method_name
method_location(method) # location
]
end
end


+ 6
- 0
locale/gitlab.pot View File

@@ -15235,6 +15235,9 @@ msgstr ""
msgid "PrometheusService|Waiting for your first deployment to an environment to find common metrics"
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"
msgstr ""

@@ -21435,6 +21438,9 @@ msgstr ""
msgid "Web terminal"
msgstr ""

msgid "WebIDE|Merge request"
msgstr ""

msgid "Webhooks"
msgstr ""



+ 1
- 1
qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true

module QA
context 'Plan', :reliable do
context 'Plan' do
describe 'Close issue' do
let(:issue) do
Resource::Issue.fabricate_via_api!


+ 70
- 5
spec/controllers/projects/services_controller_spec.rb View File

@@ -191,16 +191,81 @@ describe Projects::ServicesController do
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

describe 'GET #edit' do
before do
get :edit, params: project_params(id: 'jira')
context 'Jira service' do
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

context 'with approved services' do
it 'renders edit page' do
expect(response).to be_successful
context 'Prometheus service' do
let(:service_param) { 'prometheus' }

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


+ 1
- 1
spec/features/admin/admin_browses_logs_spec.rb View File

@@ -10,7 +10,7 @@ describe 'Admin browses logs' do
it 'shows available log files' do
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 'test.log'
expect(page).to have_link 'sidekiq.log'


+ 3
- 2
spec/features/projects/services/user_activates_prometheus_spec.rb View File

@@ -15,11 +15,12 @@ describe 'User activates Prometheus' do
click_link('Prometheus')
end

it 'activates service' do
it 'does not activate service and informs about deprecation' do
check('Active')
fill_in('API URL', with: 'http://prometheus.example.com')
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

+ 59
- 0
spec/frontend/ide/components/ide_status_mr_spec.js View 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}`);
});
});
});

+ 0
- 22
spec/frontend/ide/components/panes/right_spec.js View File

@@ -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', () => {
it('is shown if there is a packageJson and clientsidePreviewEnabled', () => {
Vue.set(store.state.entries, 'package.json', {


+ 89
- 54
spec/javascripts/ide/components/ide_status_bar_spec.js View File

@@ -1,94 +1,129 @@
import Vue from 'vue';
import _ from 'lodash';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import store from '~/ide/stores';
import ideStatusBar from '~/ide/components/ide_status_bar.vue';
import { TEST_HOST } from 'spec/test_constants';
import { createStore } from '~/ide/stores';
import IdeStatusBar from '~/ide/components/ide_status_bar.vue';
import { rightSidebarViews } from '~/ide/constants';
import { resetStore } from '../helpers';
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', () => {
let store;
let vm;

beforeEach(() => {
const Component = Vue.extend(ideStatusBar);
const createComponent = () => {
vm = createComponentWithStore(Vue.extend(IdeStatusBar), store).$mount();
};
const findMRStatus = () => vm.$el.querySelector('.js-ide-status-mr');

store.state.currentProjectId = 'abcproject';
store.state.projects.abcproject = projectData;
beforeEach(() => {
store = createStore();
store.state.currentProjectId = TEST_PROJECT_ID;
store.state.projects[TEST_PROJECT_ID] = _.clone(projectData);
store.state.currentBranchId = 'master';

vm = createComponentWithStore(Component, store).$mount();
});

afterEach(() => {
vm.$destroy();

resetStore(vm.$store);
});

it('renders the statusbar', () => {
expect(vm.$el.className).toBe('ide-status-bar');
});
describe('default', () => {
beforeEach(() => {
createComponent();
});

describe('mounted', () => {
it('triggers a setInterval', () => {
expect(vm.intervalId).not.toBe(null);
});
});

describe('commitAgeUpdate', () => {
beforeEach(function() {
jasmine.clock().install();
spyOn(vm, 'commitAgeUpdate').and.callFake(() => {});
vm.startTimer();
it('renders the statusbar', () => {
expect(vm.$el.className).toBe('ide-status-bar');
});

afterEach(function() {
jasmine.clock().uninstall();
});
describe('commitAgeUpdate', () => {
beforeEach(function() {
jasmine.clock().install();
spyOn(vm, 'commitAgeUpdate').and.callFake(() => {});
vm.startTimer();
});

it('gets called every second', () => {
expect(vm.commitAgeUpdate).not.toHaveBeenCalled();
afterEach(function() {
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', () => {
it('returns the path to the commit details', () => {
expect(vm.getCommitPath('abc123de')).toBe('/commit/abc123de');
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('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',
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}`,
},
},
commit: {
author_gravatar_url: 'www',
},
});
};
store.state.currentMergeRequestId = TEST_MERGE_REQUEST_ID;

vm.$nextTick()
.then(() => {
vm.$el.querySelector('.ide-status-pipeline button').click();
createComponent();
});

expect(vm.openRightPane).toHaveBeenCalledWith(rightSidebarViews.pipelines);
})
.then(done)
.catch(done.fail);
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);
});
});
});

+ 0
- 51
spec/javascripts/ide/components/merge_requests/info_spec.js View File

@@ -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');
});
});

+ 1
- 3
spec/javascripts/ide/stores/actions/merge_request_spec.js View File

@@ -137,9 +137,7 @@ describe('IDE store merge request actions', () => {
store
.dispatch('getMergeRequestData', { projectId: TEST_PROJECT, mergeRequestId: 1 })
.then(() => {
expect(service.getProjectMergeRequestData).toHaveBeenCalledWith(TEST_PROJECT, 1, {
render_html: true,
});
expect(service.getProjectMergeRequestData).toHaveBeenCalledWith(TEST_PROJECT, 1);

done();
})


+ 2
- 0
spec/lib/gitlab/import_export/safe_model_attributes.yml View File

@@ -30,6 +30,7 @@ Issue:
- last_edited_at
- last_edited_by_id
- discussion_locked
- health_status
Event:
- id
- target_type
@@ -824,3 +825,4 @@ Epic:
- state_id
- start_date_sourcing_epic_id
- due_date_sourcing_epic_id
- health_status

+ 39
- 0
spec/lib/gitlab/profiler_spec.rb View File

@@ -192,4 +192,43 @@ describe Gitlab::Profiler do
expect(described_class.log_load_times_by_model(null_logger)).to be_nil
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

spec/migrations/drop_activate_prometheus_services_for_shared_cluster_applications_background_migration_spec.rb → spec/migrations/drop_background_migration_jobs_spec.rb View File

@@ -1,9 +1,9 @@
# frozen_string_literal: true

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 }

describe '#up' do

+ 1
- 1
tooling/overcommit/gems.locked View File

@@ -72,4 +72,4 @@ DEPENDENCIES
scss_lint (~> 0.56.0)

BUNDLED WITH
2.1.2
1.17.3

Loading…
Cancel
Save