Skip to content
Snippets Groups Projects
Commit 0434f38e authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent c27acb1d
No related branches found
No related tags found
No related merge requests found
Showing
with 508 additions and 48 deletions
# frozen_string_literal: true
module API
module Entities
class CommitWithStats < Commit
expose :stats, using: Entities::CommitStats
end
end
end
# frozen_string_literal: true
module API
module Entities
class DiffRefs < Grape::Entity
expose :base_sha, :head_sha, :start_sha
end
end
end
# frozen_string_literal: true
module Gitlab
module Alerting
class NotificationPayloadParser
BadPayloadError = Class.new(StandardError)
DEFAULT_TITLE = 'New: Incident'
def initialize(payload)
@payload = payload.to_h.with_indifferent_access
end
def self.call(payload)
new(payload).call
end
def call
{
'annotations' => annotations,
'startsAt' => starts_at
}.compact
end
private
attr_reader :payload
def title
payload[:title].presence || DEFAULT_TITLE
end
def annotations
primary_params
.reverse_merge(flatten_secondary_params)
.transform_values(&:presence)
.compact
end
def primary_params
{
'title' => title,
'description' => payload[:description],
'monitoring_tool' => payload[:monitoring_tool],
'service' => payload[:service],
'hosts' => hosts.presence
}
end
def hosts
Array(payload[:hosts]).reject(&:blank?)
end
def current_time
Time.current.change(usec: 0).rfc3339
end
def starts_at
Time.parse(payload[:start_time].to_s).rfc3339
rescue ArgumentError
current_time
end
def secondary_params
payload.except(:start_time)
end
def flatten_secondary_params
Gitlab::Utils::SafeInlineHash.merge_keys!(secondary_params)
rescue ArgumentError
raise BadPayloadError, 'The payload is too big'
end
end
end
end
Loading
Loading
@@ -3,23 +3,18 @@
module Gitlab
module Database
# Model that can be used for querying permissions of a SQL user.
class Grant < ActiveRecord::Base
include FromUnion
self.table_name = 'information_schema.role_table_grants'
class Grant
# Returns true if the current user can create and execute triggers on the
# given table.
def self.create_and_execute_trigger?(table)
# We _must not_ use quote_table_name as this will produce double
# quotes on PostgreSQL and for "has_table_privilege" we need single
# quotes.
connection = ActiveRecord::Base.connection
quoted_table = connection.quote(table)
 
begin
from(nil)
.pluck(Arel.sql("has_table_privilege(#{quoted_table}, 'TRIGGER')"))
.first
connection.select_one("SELECT has_table_privilege(#{quoted_table}, 'TRIGGER')").present?
rescue ActiveRecord::StatementInvalid
# This error is raised when using a non-existing table name. In this
# case we just want to return false as a user technically can't
Loading
Loading
Loading
Loading
@@ -6,5 +6,3 @@ module Gitlab
end
end
end
Gitlab::DatabaseImporters::CommonMetrics.prepend_if_ee('EE::Gitlab::DatabaseImporters::CommonMetrics')
Loading
Loading
@@ -17,7 +17,9 @@ module Gitlab
# custom groups
business: 0,
response: 1,
system: 2
system: 2,
cluster_health: -100
}
end
 
Loading
Loading
@@ -31,12 +33,11 @@ module Gitlab
ha_proxy: _('Response metrics (HA Proxy)'),
aws_elb: _('Response metrics (AWS ELB)'),
nginx: _('Response metrics (NGINX)'),
kubernetes: _('System metrics (Kubernetes)')
kubernetes: _('System metrics (Kubernetes)'),
cluster_health: _('Cluster Health')
}
end
end
end
end
end
::Gitlab::DatabaseImporters::CommonMetrics::PrometheusMetricEnums.prepend_if_ee('EE::Gitlab::DatabaseImporters::CommonMetrics::PrometheusMetricEnums')
Loading
Loading
@@ -4801,9 +4801,6 @@ msgstr ""
msgid "Commit deleted"
msgstr ""
 
msgid "Commit duration in minutes for last 30 commits"
msgstr ""
msgid "Commit message"
msgstr ""
 
Loading
Loading
@@ -6813,6 +6810,9 @@ msgstr ""
msgid "Duration"
msgstr ""
 
msgid "Duration for the last 30 commits"
msgstr ""
msgid "During this process, you’ll be asked for URLs from GitLab’s side. Use the URLs shown below."
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -71,19 +71,23 @@ describe PageLimiter do
describe "#default_page_out_of_bounds_response" do
subject { instance.send(:default_page_out_of_bounds_response) }
 
after do
subject
end
it "returns a bad_request header" do
expect(instance).to receive(:head).with(:bad_request)
subject
end
end
 
describe "#record_page_limit_interception" do
subject { instance.send(:record_page_limit_interception) }
 
it "records a metric counter" do
let(:counter) { double("counter", increment: true) }
before do
allow(Gitlab::Metrics).to receive(:counter) { counter }
end
it "creates a metric counter" do
expect(Gitlab::Metrics).to receive(:counter).with(
:gitlab_page_out_of_bounds,
controller: "explore/projects",
Loading
Loading
@@ -93,5 +97,11 @@ describe PageLimiter do
 
subject
end
it "increments the counter" do
expect(counter).to receive(:increment)
subject
end
end
end
Loading
Loading
@@ -90,8 +90,12 @@ describe Explore::ProjectsController do
end
 
describe "metrics recording" do
after do
get endpoint, params: { page: page_limit + 1 }
subject { get endpoint, params: { page: page_limit + 1 } }
let(:counter) { double("counter", increment: true) }
before do
allow(Gitlab::Metrics).to receive(:counter) { counter }
end
 
it "records the interception" do
Loading
Loading
@@ -101,6 +105,8 @@ describe Explore::ProjectsController do
action: endpoint.to_s,
bot: false
)
subject
end
end
end
Loading
Loading
Loading
Loading
@@ -85,7 +85,7 @@ describe 'Project Graph', :js do
expect(page).to have_content 'Pipelines for last week'
expect(page).to have_content 'Pipelines for last month'
expect(page).to have_content 'Pipelines for last year'
expect(page).to have_content 'Commit duration in minutes for last 30 commits'
expect(page).to have_content 'Duration for the last 30 commits'
end
end
end
Loading
Loading
@@ -3,32 +3,97 @@
require 'spec_helper'
 
describe 'Projects > Snippets > User views snippets' do
let(:project) { create(:project) }
let!(:project_snippet) { create(:project_snippet, project: project, author: user) }
let!(:snippet) { create(:snippet, author: user) }
let(:snippets) { [project_snippet, snippet] } # Used by the shared examples
let_it_be(:project) { create(:project) }
let(:user) { create(:user) }
 
before do
project.add_maintainer(user)
sign_in(user)
def visit_project_snippets
visit(project_snippets_path(project))
end
 
context 'pagination' do
context 'snippets list' do
let!(:project_snippet) { create(:project_snippet, project: project, author: user) }
let!(:snippet) { create(:snippet, author: user) }
let(:snippets) { [project_snippet, snippet] } # Used by the shared examples
before do
create(:project_snippet, project: project, author: user)
allow(Snippet).to receive(:default_per_page).and_return(1)
project.add_maintainer(user)
sign_in(user)
end
context 'pagination' do
before do
create(:project_snippet, project: project, author: user)
allow(Snippet).to receive(:default_per_page).and_return(1)
 
visit project_snippets_path(project)
visit_project_snippets
end
it_behaves_like 'paginated snippets'
end
 
it_behaves_like 'paginated snippets'
it 'shows snippets' do
visit_project_snippets
expect(page).to have_link(project_snippet.title, href: project_snippet_path(project, project_snippet))
expect(page).not_to have_content(snippet.title)
end
end
 
it 'shows snippets' do
expect(page).to have_link(project_snippet.title, href: project_snippet_path(project, project_snippet))
expect(page).not_to have_content(snippet.title)
context 'when current user is a guest' do
before do
project.add_guest(user)
sign_in(user)
end
context 'when snippets list is empty' do
it 'hides New Snippet button' do
visit_project_snippets
page.within(find('.empty-state')) do
expect(page).not_to have_link('New snippet')
end
end
end
context 'when project has snippets' do
let!(:project_snippet) { create(:project_snippet, project: project, author: user) }
it 'hides New Snippet button' do
visit_project_snippets
page.within(find('.top-area')) do
expect(page).not_to have_link('New snippet')
end
end
end
end
context 'when current user is not a guest' do
before do
project.add_developer(user)
sign_in(user)
end
context 'when snippets list is empty' do
it 'shows New Snippet button' do
visit_project_snippets
page.within(find('.empty-state')) do
expect(page).to have_link('New snippet')
end
end
end
context 'when project has snippets' do
let!(:project_snippet) { create(:project_snippet, project: project, author: user) }
it 'shows New Snippet button' do
visit_project_snippets
page.within(find('.top-area')) do
expect(page).to have_link('New snippet')
end
end
end
end
end
Loading
Loading
@@ -5,7 +5,7 @@ require 'spec_helper'
describe 'Task Lists' do
include Warden::Test::Helpers
 
let(:project) { create(:project, :repository) }
let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
 
Loading
Loading
@@ -122,6 +122,7 @@ describe 'Task Lists' do
 
it 'provides a summary on Issues#index' do
visit project_issues_path(project)
expect(page).to have_content("2 of 6 tasks completed")
end
end
Loading
Loading
@@ -191,6 +192,7 @@ describe 'Task Lists' do
 
it 'is only editable by author', :js do
visit_issue(project, issue)
expect(page).to have_selector('.js-task-list-container')
 
gitlab_sign_out
Loading
Loading
@@ -237,10 +239,7 @@ describe 'Task Lists' do
visit project_merge_request_path(project, merge)
end
 
describe 'multiple tasks' do
let(:project) { create(:project, :repository) }
let!(:merge) { create(:merge_request, :simple, description: markdown, author: user, source_project: project) }
shared_examples 'multiple tasks' do
it 'renders for description' do
visit_merge_request(project, merge)
 
Loading
Loading
@@ -261,23 +260,40 @@ describe 'Task Lists' do
expect(page).to have_selector('a.btn-close')
end
 
it 'is only editable by author' do
it 'is only editable by author', :js do
visit_merge_request(project, merge)
expect(page).to have_selector('.js-task-list-container')
expect(page).to have_selector('li.task-list-item.enabled', count: 6)
 
logout(:user)
login_as(user2)
visit current_path
expect(page).not_to have_selector('.js-task-list-container')
expect(page).to have_selector('li.task-list-item.enabled', count: 0)
expect(page).to have_selector('li.task-list-item input[disabled]', count: 6)
end
end
context 'when merge request is open' do
let!(:merge) { create(:merge_request, :simple, description: markdown, author: user, source_project: project) }
it_behaves_like 'multiple tasks'
 
it 'provides a summary on MergeRequests#index' do
visit project_merge_requests_path(project)
expect(page).to have_content("2 of 6 tasks completed")
end
end
 
context 'when merge request is closed' do
let!(:merge) { create(:merge_request, :closed, :simple, description: markdown, author: user, source_project: project) }
it_behaves_like 'multiple tasks'
end
describe 'single incomplete task' do
let!(:merge) { create(:merge_request, :simple, description: singleIncompleteMarkdown, author: user, source_project: project) }
 
Loading
Loading
@@ -291,6 +307,7 @@ describe 'Task Lists' do
 
it 'provides a summary on MergeRequests#index' do
visit project_merge_requests_path(project)
expect(page).to have_content("0 of 1 task completed")
end
end
Loading
Loading
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StatisticsList matches the snapshot 1`] = `
<ul>
<li>
<span>
Total:
</span>
<strong>
4 pipelines
</strong>
</li>
<li>
<span>
Successful:
</span>
<strong>
2 pipelines
</strong>
</li>
<li>
<span>
Failed:
</span>
<strong>
2 pipelines
</strong>
</li>
<li>
<span>
Success ratio:
</span>
<strong>
50%
</strong>
</li>
</ul>
`;
import { shallowMount } from '@vue/test-utils';
import { GlColumnChart } from '@gitlab/ui/dist/charts';
import Component from '~/projects/pipelines/charts/components/app';
import StatisticsList from '~/projects/pipelines/charts/components/statistics_list';
import { counts, timesChartData } from '../mock_data';
describe('ProjectsPipelinesChartsApp', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(Component, {
propsData: {
counts,
timesChartData,
},
});
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('overall statistics', () => {
it('displays the statistics list', () => {
const list = wrapper.find(StatisticsList);
expect(list.exists()).toBeTruthy();
expect(list.props('counts')).toBe(counts);
});
it('displays the commit duration chart', () => {
const chart = wrapper.find(GlColumnChart);
expect(chart.exists()).toBeTruthy();
expect(chart.props('yAxisTitle')).toBe('Minutes');
expect(chart.props('xAxisTitle')).toBe('Commit');
expect(chart.props('data')).toBe(wrapper.vm.timesChartTransformedData);
expect(chart.props('option')).toBe(wrapper.vm.$options.timesChartOptions);
});
});
});
import { shallowMount } from '@vue/test-utils';
import Component from '~/projects/pipelines/charts/components/statistics_list';
import { counts } from '../mock_data';
describe('StatisticsList', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(Component, {
propsData: {
counts,
},
});
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
});
export const counts = {
failed: 2,
success: 2,
total: 4,
successRatio: 50,
};
export const timesChartData = {
labels: ['as1234', 'kh423hy', 'ji56bvg', 'th23po'],
values: [5, 3, 7, 4],
};
# frozen_string_literal: true
require 'fast_spec_helper'
describe Gitlab::Alerting::NotificationPayloadParser do
describe '.call' do
let(:starts_at) { Time.current.change(usec: 0) }
let(:payload) do
{
'title' => 'alert title',
'start_time' => starts_at.rfc3339,
'description' => 'Description',
'monitoring_tool' => 'Monitoring tool name',
'service' => 'Service',
'hosts' => ['gitlab.com']
}
end
subject { described_class.call(payload) }
it 'returns Prometheus-like payload' do
is_expected.to eq(
{
'annotations' => {
'title' => 'alert title',
'description' => 'Description',
'monitoring_tool' => 'Monitoring tool name',
'service' => 'Service',
'hosts' => ['gitlab.com']
},
'startsAt' => starts_at.rfc3339
}
)
end
context 'when title is blank' do
before do
payload[:title] = ''
end
it 'sets a predefined title' do
expect(subject.dig('annotations', 'title')).to eq('New: Incident')
end
end
context 'when hosts attribute is a string' do
before do
payload[:hosts] = 'gitlab.com'
end
it 'returns hosts as an array of one element' do
expect(subject.dig('annotations', 'hosts')).to eq(['gitlab.com'])
end
end
context 'when the time is in unsupported format' do
before do
payload[:start_time] = 'invalid/date/format'
end
it 'sets startsAt to a current time in RFC3339 format' do
expect(subject['startsAt']).to eq(starts_at.rfc3339)
end
end
context 'when payload is blank' do
let(:payload) { {} }
it 'returns default parameters' do
is_expected.to eq(
'annotations' => { 'title' => 'New: Incident' },
'startsAt' => starts_at.rfc3339
)
end
end
context 'when payload attributes have blank lines' do
let(:payload) do
{
'title' => '',
'start_time' => '',
'description' => '',
'monitoring_tool' => '',
'service' => '',
'hosts' => ['']
}
end
it 'returns default parameters' do
is_expected.to eq(
'annotations' => { 'title' => 'New: Incident' },
'startsAt' => starts_at.rfc3339
)
end
end
context 'when payload has secondary params' do
let(:payload) do
{
'description' => 'Description',
'additional' => {
'params' => {
'1' => 'Some value 1',
'2' => 'Some value 2',
'blank' => ''
}
}
}
end
it 'adds secondary params to annotations' do
is_expected.to eq(
'annotations' => {
'title' => 'New: Incident',
'description' => 'Description',
'additional.params.1' => 'Some value 1',
'additional.params.2' => 'Some value 2'
},
'startsAt' => starts_at.rfc3339
)
end
end
context 'when secondary params hash is too big' do
before do
allow(Gitlab::Utils::SafeInlineHash).to receive(:merge_keys!).and_raise(ArgumentError)
end
it 'catches and re-raises an error' do
expect { subject }.to raise_error Gitlab::Alerting::NotificationPayloadParser::BadPayloadError, 'The payload is too big'
end
end
end
end
Loading
Loading
@@ -67,6 +67,7 @@ describe PrometheusMetric do
it_behaves_like 'group_title', :business, 'Business metrics (Custom)'
it_behaves_like 'group_title', :response, 'Response metrics (Custom)'
it_behaves_like 'group_title', :system, 'System metrics (Custom)'
it_behaves_like 'group_title', :cluster_health, 'Cluster Health'
end
 
describe '#priority' do
Loading
Loading
@@ -82,6 +83,7 @@ describe PrometheusMetric do
:business | 0
:response | -5
:system | -10
:cluster_health | 10
end
 
with_them do
Loading
Loading
@@ -106,6 +108,7 @@ describe PrometheusMetric do
:business | %w()
:response | %w()
:system | %w()
:cluster_health | %w(container_memory_usage_bytes container_cpu_usage_seconds_total)
end
 
with_them do
Loading
Loading
Loading
Loading
@@ -51,6 +51,22 @@ describe ReleasePresenter do
end
end
 
describe '#self_url' do
subject { presenter.self_url }
it 'returns its own url' do
is_expected.to match /#{project_release_url(project, release)}/
end
context 'when release_show_page feature flag is disabled' do
before do
stub_feature_flags(release_show_page: false)
end
it { is_expected.to be_nil }
end
end
describe '#merge_requests_url' do
subject { presenter.merge_requests_url }
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment