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

Add latest changes from gitlab-org/gitlab@master

parent ccf37fd3
No related branches found
No related tags found
No related merge requests found
Showing
with 269 additions and 163 deletions
- return unless dashboard_nav_link?(:analytics)
= nav_link(controller: [:dev_ops_score, :cohorts], html_options: { class: "d-none d-xl-block"}) do
= link_to instance_statistics_root_path, class: 'chart-icon', title: _('Analytics'), aria: { label: _('Analytics') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('chart', size: 18)
Loading
Loading
@@ -47,10 +47,7 @@
 
%li.dropdown
= render_if_exists 'dashboard/nav_link_list'
- if can?(current_user, :read_instance_statistics)
= nav_link(controller: [:dev_ops_score, :cohorts]) do
= link_to instance_statistics_root_path do
= _('Instance Statistics')
- if current_user.admin?
= nav_link(controller: 'admin/dashboard') do
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link d-xl-none' do
Loading
Loading
@@ -69,6 +66,8 @@
= link_to sherlock_transactions_path, class: 'admin-icon' do
= _('Sherlock Transactions')
 
= render_if_exists 'layouts/nav/analytics_link'
- if current_user.admin?
= nav_link(controller: 'admin/dashboard', html_options: { class: "d-none d-xl-block"}) do
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link', title: _('Admin Area'), aria: { label: _('Admin Area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
Loading
Loading
- return unless dashboard_nav_link?(:analytics)
= nav_link(controller: [:dev_ops_score, :cohorts]) do
= link_to instance_statistics_root_path, class: 'd-xl-none' do
= _('Analytics')
.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll
.context-header
= link_to instance_statistics_root_path, title: _('Instance Statistics') do
= link_to instance_statistics_root_path, title: _('Analytics') do
.avatar-container.s40.settings-avatar
= sprite_icon('chart', size: 24)
.sidebar-context-title= _('Instance Statistics')
.sidebar-context-title= _('Analytics')
%ul.sidebar-top-level-items
= nav_link(controller: :dev_ops_score) do
= link_to instance_statistics_dev_ops_score_index_path do
.nav-icon-container
= sprite_icon('comment')
%span.nav-item-name
= _('DevOps Score')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :dev_ops_score, html_options: { class: "fly-out-top-item" } ) do
= link_to instance_statistics_dev_ops_score_index_path do
%strong.fly-out-top-item-name
= _('DevOps Score')
- if Gitlab::CurrentSettings.usage_ping_enabled
= nav_link(controller: :cohorts) do
= link_to instance_statistics_cohorts_path do
.nav-icon-container
= sprite_icon('users')
%span.nav-item-name
= _('Cohorts')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :cohorts, html_options: { class: "fly-out-top-item" } ) do
= link_to instance_statistics_cohorts_path do
%strong.fly-out-top-item-name
= _('Cohorts')
= render 'layouts/nav/sidebar/instance_statistics_links'
 
= render 'shared/sidebar_toggle_button'
- return unless dashboard_nav_link?(:analytics)
= nav_link(controller: :dev_ops_score) do
= link_to instance_statistics_dev_ops_score_index_path do
.nav-icon-container
= sprite_icon('comment')
%span.nav-item-name
= _('DevOps Score')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :dev_ops_score, html_options: { class: "fly-out-top-item" } ) do
= link_to instance_statistics_dev_ops_score_index_path do
%strong.fly-out-top-item-name
= _('DevOps Score')
- if Gitlab::CurrentSettings.usage_ping_enabled
= nav_link(controller: :cohorts) do
= link_to instance_statistics_cohorts_path do
.nav-icon-container
= sprite_icon('users')
%span.nav-item-name
= _('Cohorts')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :cohorts, html_options: { class: "fly-out-top-item" } ) do
= link_to instance_statistics_cohorts_path do
%strong.fly-out-top-item-name
= _('Cohorts')
Loading
Loading
@@ -12,7 +12,7 @@
= _('To link Sentry to GitLab, enter your Sentry URL and Auth Token.')
= link_to _('More information'), help_page_path('user/project/operations/error_tracking'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
.js-error-tracking-form{ data: { list_projects_endpoint: list_projects_project_error_tracking_index_path(@project, format: :json),
.js-error-tracking-form{ data: { list_projects_endpoint: project_error_tracking_projects_path(@project, format: :json),
operations_settings_endpoint: project_settings_operations_path(@project),
project: error_tracking_setting_project_json,
api_host: setting.api_host,
Loading
Loading
---
title: Add activity across all projects to /events endpoint
merge_request: 19816
author: briankabiro
type: changed
---
title: Move instance statistics into analytics namespace
merge_request: 21112
author:
type: changed
---
title: Reduce CommitIsAncestor RPCs with environments
merge_request: 21778
author:
type: performance
Loading
Loading
@@ -256,6 +256,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
 
namespace :error_tracking do
resources :projects, only: :index
end
resources :error_tracking, only: [:index], controller: :error_tracking do
collection do
get ':issue_id/details',
Loading
Loading
@@ -264,7 +268,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get ':issue_id/stack_trace',
to: 'error_tracking#stack_trace',
as: 'stack_trace'
post :list_projects
end
end
 
Loading
Loading
Loading
Loading
@@ -66,12 +66,13 @@ Parameters:
| `target_type` | string | no | Include only events of a particular [target type][target-types] |
| `before` | date | no | Include only events created before a particular date. Please see [here for the supported format][date-formatting] |
| `after` | date | no | Include only events created after a particular date. Please see [here for the supported format][date-formatting] |
| `scope` | string | no | Include all events across a user's projects. |
| `sort` | string | no | Sort events in `asc` or `desc` order by `created_at`. Default is `desc` |
 
Example request:
 
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01&scope=all
```
 
Example response:
Loading
Loading
Loading
Loading
@@ -9776,9 +9776,6 @@ msgid_plural "Instances"
msgstr[0] ""
msgstr[1] ""
 
msgid "Instance Statistics"
msgstr ""
msgid "Instance Statistics visibility"
msgstr ""
 
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Projects::ErrorTracking::ProjectsController do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
before do
sign_in(user)
project.add_maintainer(user)
end
describe 'POST #index' do
context 'with insufficient permissions' do
before do
project.add_guest(user)
end
it 'returns 404' do
get :index, params: list_projects_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with an anonymous user' do
before do
sign_out(user)
end
it 'redirects to sign-in page' do
get :index, params: list_projects_params
expect(response).to have_gitlab_http_status(:redirect)
end
end
context 'with authorized user' do
let(:list_projects_service) { spy(:list_projects_service) }
let(:sentry_project) { build(:error_tracking_project) }
let(:query_params) do
list_projects_params.slice(:api_host, :token)
end
before do
allow(ErrorTracking::ListProjectsService)
.to receive(:new).with(project, user, query_params)
.and_return(list_projects_service)
end
context 'service result is successful' do
before do
expect(list_projects_service).to receive(:execute)
.and_return(status: :success, projects: [sentry_project])
end
it 'returns a list of projects' do
get :index, params: list_projects_params
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('error_tracking/list_projects')
expect(json_response['projects']).to eq([sentry_project].as_json)
end
end
context 'service result is erroneous' do
let(:error_message) { 'error message' }
context 'without http_status' do
before do
expect(list_projects_service).to receive(:execute)
.and_return(status: :error, message: error_message)
end
it 'returns 400 with message' do
get :index, params: list_projects_params
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq(error_message)
end
end
context 'with explicit http_status' do
let(:http_status) { :no_content }
before do
expect(list_projects_service).to receive(:execute).and_return(
status: :error,
message: error_message,
http_status: http_status
)
end
it 'returns http_status with message' do
get :index, params: list_projects_params
expect(response).to have_gitlab_http_status(http_status)
expect(json_response['message']).to eq(error_message)
end
end
end
end
private
def list_projects_params(opts = {})
project_params(
format: :json,
api_host: 'gitlab.com',
token: 'token'
)
end
end
private
def project_params(opts = {})
opts.reverse_merge(namespace_id: project.namespace, project_id: project)
end
end
Loading
Loading
@@ -179,113 +179,6 @@ describe Projects::ErrorTrackingController do
end
end
 
describe 'POST #list_projects' do
context 'with insufficient permissions' do
before do
project.add_guest(user)
end
it 'returns 404' do
post :list_projects, params: list_projects_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with an anonymous user' do
before do
sign_out(user)
end
it 'redirects to sign-in page' do
post :list_projects, params: list_projects_params
expect(response).to have_gitlab_http_status(:redirect)
end
end
context 'with authorized user' do
let(:list_projects_service) { spy(:list_projects_service) }
let(:sentry_project) { build(:error_tracking_project) }
let(:permitted_params) do
ActionController::Parameters.new(
list_projects_params[:error_tracking_setting]
).permit!
end
before do
allow(ErrorTracking::ListProjectsService)
.to receive(:new).with(project, user, permitted_params)
.and_return(list_projects_service)
end
context 'service result is successful' do
before do
expect(list_projects_service).to receive(:execute)
.and_return(status: :success, projects: [sentry_project])
end
it 'returns a list of projects' do
post :list_projects, params: list_projects_params
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('error_tracking/list_projects')
expect(json_response['projects']).to eq([sentry_project].as_json)
end
end
context 'service result is erroneous' do
let(:error_message) { 'error message' }
context 'without http_status' do
before do
expect(list_projects_service).to receive(:execute)
.and_return(status: :error, message: error_message)
end
it 'returns 400 with message' do
get :list_projects, params: list_projects_params
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq(error_message)
end
end
context 'with explicit http_status' do
let(:http_status) { :no_content }
before do
expect(list_projects_service).to receive(:execute).and_return(
status: :error,
message: error_message,
http_status: http_status
)
end
it 'returns http_status with message' do
get :list_projects, params: list_projects_params
expect(response).to have_gitlab_http_status(http_status)
expect(json_response['message']).to eq(error_message)
end
end
end
end
private
def list_projects_params(opts = {})
project_params(
format: :json,
error_tracking_setting: {
api_host: 'gitlab.com',
token: 'token'
}
)
end
end
describe 'GET #issue_details' do
let_it_be(:issue_id) { 1234 }
 
Loading
Loading
Loading
Loading
@@ -2,7 +2,7 @@
 
require 'spec_helper'
 
describe 'Showing instance statistics' do
describe 'Showing analytics' do
before do
sign_in user if user
end
Loading
Loading
@@ -13,10 +13,10 @@ describe 'Showing instance statistics' do
context 'for unauthenticated users' do
let(:user) { nil }
 
it 'does not show the instance statistics link' do
it 'does not show the Analytics link' do
subject
 
expect(page).not_to have_link('Instance Statistics')
expect(page).not_to have_link('Analytics')
end
end
 
Loading
Loading
@@ -28,10 +28,10 @@ describe 'Showing instance statistics' do
stub_application_setting(instance_statistics_visibility_private: false)
end
 
it 'shows the instance statistics link' do
it 'shows the analytics link' do
subject
 
expect(page).to have_link('Instance Statistics')
expect(page).to have_link('Analytics')
end
end
 
Loading
Loading
@@ -40,10 +40,14 @@ describe 'Showing instance statistics' do
stub_application_setting(instance_statistics_visibility_private: true)
end
 
it 'shows the instance statistics link' do
it 'does not show the analytics link' do
subject
 
expect(page).not_to have_link('Instance Statistics')
# Skipping this test on EE as there is an EE specifc spec for this functionality
# ee/spec/features/dashboards/analytics_spec.rb
skip if Gitlab.ee?
expect(page).not_to have_link('Analytics')
end
end
end
Loading
Loading
@@ -51,10 +55,10 @@ describe 'Showing instance statistics' do
context 'for admins' do
let(:user) { create(:admin) }
 
it 'shows the instance statistics link' do
it 'shows the analytics link' do
subject
 
expect(page).to have_link('Instance Statistics')
expect(page).to have_link('Analytics')
end
end
end
Loading
Loading
@@ -13,17 +13,22 @@ describe EnvironmentsFinder do
end
 
context 'tagged deployment' do
let(:environment_two) { create(:environment, project: project) }
# Environments need to include commits, so rewind two commits to fit
let(:commit) { project.commit('HEAD~2') }
before do
create(:deployment, :success, environment: environment, ref: 'v1.1.0', tag: true, sha: project.commit.id)
create(:deployment, :success, environment: environment, ref: 'v1.0.0', tag: true, sha: project.commit.id)
create(:deployment, :success, environment: environment_two, ref: 'v1.1.0', tag: true, sha: project.commit('HEAD~1').id)
end
 
it 'returns environment when with_tags is set' do
expect(described_class.new(project, user, ref: 'master', commit: project.commit, with_tags: true).execute)
.to contain_exactly(environment)
expect(described_class.new(project, user, ref: 'master', commit: commit, with_tags: true).execute)
.to contain_exactly(environment, environment_two)
end
 
it 'does not return environment when no with_tags is set' do
expect(described_class.new(project, user, ref: 'master', commit: project.commit).execute)
expect(described_class.new(project, user, ref: 'master', commit: commit).execute)
.to be_empty
end
 
Loading
Loading
@@ -31,6 +36,21 @@ describe EnvironmentsFinder do
expect(described_class.new(project, user, ref: 'master', commit: project.commit('feature')).execute)
.to be_empty
end
it 'returns environment when with_tags is set' do
expect(described_class.new(project, user, ref: 'master', commit: commit, with_tags: true).execute)
.to contain_exactly(environment, environment_two)
end
# We expect two Gitaly calls: FindCommit, CommitIsAncestor
# This tests to ensure we don't call one CommitIsAncestor per environment
it 'only calls Gitaly twice when multiple environments are present', :request_store do
expect do
result = described_class.new(project, user, ref: 'master', commit: commit, with_tags: true, find_latest: true).execute
expect(result).to contain_exactly(environment_two)
end.to change { Gitlab::GitalyClient.get_request_count }.by(2)
end
end
 
context 'branch deployment' do
Loading
Loading
Loading
Loading
@@ -5,8 +5,10 @@ require 'spec_helper'
describe EventsFinder do
let(:user) { create(:user) }
let(:other_user) { create(:user) }
let(:project1) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
let(:project2) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
let(:closed_issue) { create(:closed_issue, project: project1, author: user) }
let(:opened_merge_request) { create(:merge_request, source_project: project2, author: user) }
let!(:closed_issue_event) { create(:event, project: project1, author: user, target: closed_issue, action: Event::CLOSED, created_at: Date.new(2016, 12, 30)) }
Loading
Loading
@@ -15,6 +17,8 @@ describe EventsFinder do
let(:opened_merge_request2) { create(:merge_request, source_project: project2, author: user) }
let!(:closed_issue_event2) { create(:event, project: project1, author: user, target: closed_issue, action: Event::CLOSED, created_at: Date.new(2016, 2, 2)) }
let!(:opened_merge_request_event2) { create(:event, project: project2, author: user, target: opened_merge_request, action: Event::CREATED, created_at: Date.new(2017, 2, 2)) }
let(:opened_merge_request3) { create(:merge_request, source_project: project1, author: other_user) }
let!(:other_developer_event) { create(:event, project: project1, author: other_user, target: opened_merge_request3, action: Event::CREATED) }
 
let(:public_project) { create(:project, :public, creator_id: user.id, namespace: user.namespace) }
let(:confidential_issue) { create(:closed_issue, confidential: true, project: public_project, author: user) }
Loading
Loading
@@ -55,6 +59,28 @@ describe EventsFinder do
end
end
 
context 'dashboard events' do
before do
project1.add_developer(other_user)
end
context 'scope is `all`' do
it 'includes activity of other users' do
events = described_class.new(source: user, current_user: user, scope: 'all').execute
expect(events).to include(other_developer_event)
end
end
context 'scope is not `all`' do
it 'does not include activity of other users' do
events = described_class.new(source: user, current_user: user, scope: '').execute
expect(events).not_to include(other_developer_event)
end
end
end
context 'when targeting a project' do
it 'returns project events between specified dates filtered on action and type' do
events = described_class.new(source: project1, current_user: user, action: 'closed', target_type: 'issue', after: Date.new(2016, 12, 1), before: Date.new(2017, 1, 1)).execute
Loading
Loading
Loading
Loading
@@ -28,7 +28,7 @@ describe('error tracking settings actions', () => {
});
 
it('should request and transform the project list', done => {
mock.onPost(TEST_HOST).reply(() => [200, { projects: projectList }]);
mock.onGet(TEST_HOST).reply(() => [200, { projects: projectList }]);
testAction(
actions.fetchProjects,
null,
Loading
Loading
@@ -42,14 +42,14 @@ describe('error tracking settings actions', () => {
},
],
() => {
expect(mock.history.post.length).toBe(1);
expect(mock.history.get.length).toBe(1);
done();
},
);
});
 
it('should handle a server error', done => {
mock.onPost(`${TEST_HOST}.json`).reply(() => [400]);
mock.onGet(`${TEST_HOST}.json`).reply(() => [400]);
testAction(
actions.fetchProjects,
null,
Loading
Loading
@@ -62,7 +62,7 @@ describe('error tracking settings actions', () => {
},
],
() => {
expect(mock.history.post.length).toBe(1);
expect(mock.history.get.length).toBe(1);
done();
},
);
Loading
Loading
Loading
Loading
@@ -36,9 +36,13 @@ describe Environment, :use_clean_rails_memory_store_caching do
let!(:deployment2) { create(:deployment, environment: environment2) }
let!(:deployment3) { create(:deployment, environment: environment1) }
 
it 'returns the environments in order of having been last deployed' do
it 'returns the environments in ascending order of having been last deployed' do
expect(project.environments.order_by_last_deployed_at.to_a).to eq([environment3, environment2, environment1])
end
it 'returns the environments in descending order of having been last deployed' do
expect(project.environments.order_by_last_deployed_at_desc.to_a).to eq([environment1, environment2, environment3])
end
end
 
describe 'state machine' do
Loading
Loading
Loading
Loading
@@ -2322,6 +2322,10 @@ describe MergeRequest do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:source_branch) { merge_request.source_branch }
let(:target_branch) { merge_request.target_branch }
let(:source_oid) { project.commit(source_branch).id }
let(:target_oid) { project.commit(target_branch).id }
 
before do
merge_request.source_project.add_maintainer(user)
Loading
Loading
@@ -2332,13 +2336,21 @@ describe MergeRequest do
let(:environments) { create_list(:environment, 3, project: project) }
 
before do
create(:deployment, :success, environment: environments.first, ref: 'master', sha: project.commit('master').id)
create(:deployment, :success, environment: environments.second, ref: 'feature', sha: project.commit('feature').id)
create(:deployment, :success, environment: environments.first, ref: source_branch, sha: source_oid)
create(:deployment, :success, environment: environments.second, ref: target_branch, sha: target_oid)
end
 
it 'selects deployed environments' do
expect(merge_request.environments_for(user)).to contain_exactly(environments.first)
end
it 'selects latest deployed environment' do
latest_environment = create(:environment, project: project)
create(:deployment, :success, environment: latest_environment, ref: source_branch, sha: source_oid)
expect(merge_request.environments_for(user)).to eq([environments.first, latest_environment])
expect(merge_request.environments_for(user, latest: true)).to contain_exactly(latest_environment)
end
end
 
context 'with environments on source project' do
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