Commit e95a9759 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 6ac3c679
<script> <script>
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import { GlEmptyState, GlButton, GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui'; import {
GlEmptyState,
GlButton,
GlLink,
GlLoadingIcon,
GlTable,
GlSearchBoxByType,
} from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { __ } from '~/locale'; import { __ } from '~/locale';
...@@ -20,6 +27,7 @@ export default { ...@@ -20,6 +27,7 @@ export default {
GlLink, GlLink,
GlLoadingIcon, GlLoadingIcon,
GlTable, GlTable,
GlSearchBoxByType,
Icon, Icon,
TimeAgo, TimeAgo,
}, },
...@@ -48,8 +56,17 @@ export default { ...@@ -48,8 +56,17 @@ export default {
required: true, required: true,
}, },
}, },
data() {
return {
errorSearchQuery: '',
};
},
computed: { computed: {
...mapState(['errors', 'externalUrl', 'loading']), ...mapState(['errors', 'externalUrl', 'loading']),
...mapGetters(['filterErrorsByTitle']),
filteredErrors() {
return this.errorSearchQuery ? this.filterErrorsByTitle(this.errorSearchQuery) : this.errors;
},
}, },
created() { created() {
if (this.errorTrackingEnabled) { if (this.errorTrackingEnabled) {
...@@ -71,10 +88,17 @@ export default { ...@@ -71,10 +88,17 @@ export default {
<gl-loading-icon :size="3" /> <gl-loading-icon :size="3" />
</div> </div>
<div v-else> <div v-else>
<div class="d-flex justify-content-end"> <div class="d-flex flex-row justify-content-around bg-secondary border">
<gl-search-box-by-type
v-model="errorSearchQuery"
class="col-lg-10 m-3 p-0"
:placeholder="__('Search or filter results...')"
type="search"
autofocus
/>
<gl-button <gl-button
v-track-event="trackViewInSentryOptions(externalUrl)" v-track-event="trackViewInSentryOptions(externalUrl)"
class="my-3 ml-auto" class="m-3"
variant="primary" variant="primary"
:href="externalUrl" :href="externalUrl"
target="_blank" target="_blank"
...@@ -84,7 +108,14 @@ export default { ...@@ -84,7 +108,14 @@ export default {
</gl-button> </gl-button>
</div> </div>
<gl-table :items="errors" :fields="$options.fields" :show-empty="true" fixed stacked="sm"> <gl-table
class="mt-3"
:items="filteredErrors"
:fields="$options.fields"
:show-empty="true"
fixed
stacked="sm"
>
<template slot="HEAD_events" slot-scope="data"> <template slot="HEAD_events" slot-scope="data">
<div class="text-md-right">{{ data.label }}</div> <div class="text-md-right">{{ data.label }}</div>
</template> </template>
......
export const filterErrorsByTitle = state => errorQuery =>
state.errors.filter(error => error.title.match(new RegExp(`${errorQuery}`, 'i')));
export default () => {};
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import * as actions from './actions'; import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations'; import mutations from './mutations';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -14,6 +15,7 @@ export const createStore = () => ...@@ -14,6 +15,7 @@ export const createStore = () =>
}, },
actions, actions,
mutations, mutations,
getters,
}); });
export default createStore(); export default createStore();
...@@ -156,15 +156,22 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -156,15 +156,22 @@ class Projects::PipelinesController < Projects::ApplicationController
def test_report def test_report
return unless Feature.enabled?(:junit_pipeline_view, project) return unless Feature.enabled?(:junit_pipeline_view, project)
if pipeline_test_report == :error respond_to do |format|
render json: { status: :error_parsing_report } format.html do
return render 'show'
end end
format.json do
if pipeline_test_report == :error
render json: { status: :error_parsing_report }
else
render json: TestReportSerializer render json: TestReportSerializer
.new(current_user: @current_user) .new(current_user: @current_user)
.represent(pipeline_test_report) .represent(pipeline_test_report)
end end
end
end
end
private private
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
= author_avatar(commit, size: 36, has_tooltip: false) = author_avatar(commit, size: 36, has_tooltip: false)
.commit-row-title .commit-row-title
%span.item-title.str-truncated-100 %span.item-title.str-truncated-100
= link_to_markdown commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title = link_to commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title
.float-right .float-right
= link_to commit.short_id, project_commit_path(@project, commit), class: "commit-sha" = link_to commit.short_id, project_commit_path(@project, commit), class: "commit-sha"
&nbsp; &nbsp;
......
---
title: Drop `id` column from `ci_build_trace_sections` table
merge_request: 18741
author:
type: changed
---
title: Do not render links in commit message on blame page
merge_request: 19128
author:
type: performance
---
title: Search list of Sentry errors by title in Gitlab
merge_request: 18772
author:
type: added
---
title: Fix Gitaly call duration measurements
merge_request: 18785
author:
type: fixed
# frozen_string_literal: true
class DropCiBuildTraceSectionsId < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
##
# This column has already been ignored since 12.4
# See https://gitlab.com/gitlab-org/gitlab/issues/32569
remove_column :ci_build_trace_sections, :id
end
def down
##
# We don't backfill serial ids as it's not used in application code
# and quite expensive process.
add_column :ci_build_trace_sections, :id, :bigint
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_10_17_094449) do ActiveRecord::Schema.define(version: 2019_10_17_180026) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm" enable_extension "pg_trgm"
...@@ -599,7 +599,7 @@ ActiveRecord::Schema.define(version: 2019_10_17_094449) do ...@@ -599,7 +599,7 @@ ActiveRecord::Schema.define(version: 2019_10_17_094449) do
t.index ["project_id", "name"], name: "index_ci_build_trace_section_names_on_project_id_and_name", unique: true t.index ["project_id", "name"], name: "index_ci_build_trace_section_names_on_project_id_and_name", unique: true
end end
create_table "ci_build_trace_sections", id: :serial, force: :cascade do |t| create_table "ci_build_trace_sections", id: false, force: :cascade do |t|
t.integer "project_id", null: false t.integer "project_id", null: false
t.datetime "date_start", null: false t.datetime "date_start", null: false
t.datetime "date_end", null: false t.datetime "date_end", null: false
......
...@@ -41,5 +41,6 @@ NOTE: **Note:** ...@@ -41,5 +41,6 @@ NOTE: **Note:**
You will need at least Reporter [permissions](../../permissions.md) to view the Error Tracking list. You will need at least Reporter [permissions](../../permissions.md) to view the Error Tracking list.
The Error Tracking list may be found at **Operations > Error Tracking** in your project's sidebar. The Error Tracking list may be found at **Operations > Error Tracking** in your project's sidebar.
Errors can be filtered by title.
![Error Tracking list](img/error_tracking_list.png) ![Error Tracking list](img/error_tracking_list.png)
...@@ -142,18 +142,39 @@ module Gitlab ...@@ -142,18 +142,39 @@ module Gitlab
# kwargs.merge(deadline: Time.now + 10) # kwargs.merge(deadline: Time.now + 10)
# end # end
# #
def self.call(storage, service, rpc, request, remote_storage: nil, timeout: default_timeout) def self.call(storage, service, rpc, request, remote_storage: nil, timeout: default_timeout, &block)
start = Gitlab::Metrics::System.monotonic_time self.measure_timings(service, rpc, request) do
request_hash = request.is_a?(Google::Protobuf::MessageExts) ? request.to_h : {} self.execute(storage, service, rpc, request, remote_storage: remote_storage, timeout: timeout, &block)
end
end
# This method is like GitalyClient.call but should be used with
# Gitaly streaming RPCs. It measures how long the the RPC took to
# produce the full response, not just the initial response.
def self.streaming_call(storage, service, rpc, request, remote_storage: nil, timeout: default_timeout)
self.measure_timings(service, rpc, request) do
response = self.execute(storage, service, rpc, request, remote_storage: remote_storage, timeout: timeout)
yield(response)
end
end
def self.execute(storage, service, rpc, request, remote_storage:, timeout:)
enforce_gitaly_request_limits(:call) enforce_gitaly_request_limits(:call)
kwargs = request_kwargs(storage, timeout: timeout.to_f, remote_storage: remote_storage) kwargs = request_kwargs(storage, timeout: timeout.to_f, remote_storage: remote_storage)
kwargs = yield(kwargs) if block_given? kwargs = yield(kwargs) if block_given?
stub(service, storage).__send__(rpc, request, kwargs) # rubocop:disable GitlabSecurity/PublicSend stub(service, storage).__send__(rpc, request, kwargs) # rubocop:disable GitlabSecurity/PublicSend
end
def self.measure_timings(service, rpc, request)
start = Gitlab::Metrics::System.monotonic_time
yield
ensure ensure
duration = Gitlab::Metrics::System.monotonic_time - start duration = Gitlab::Metrics::System.monotonic_time - start
request_hash = request.is_a?(Google::Protobuf::MessageExts) ? request.to_h : {}
# Keep track, separately, for the performance bar # Keep track, separately, for the performance bar
self.query_time += duration self.query_time += duration
......
...@@ -200,9 +200,10 @@ module Gitlab ...@@ -200,9 +200,10 @@ module Gitlab
to: to to: to
) )
response = GitalyClient.call(@repository.storage, :commit_service, :commits_between, request, timeout: GitalyClient.medium_timeout) GitalyClient.streaming_call(@repository.storage, :commit_service, :commits_between, request, timeout: GitalyClient.medium_timeout) do |response|
consume_commits_response(response) consume_commits_response(response)
end end
end
def diff_stats(left_commit_sha, right_commit_sha) def diff_stats(left_commit_sha, right_commit_sha)
request = Gitaly::DiffStatsRequest.new( request = Gitaly::DiffStatsRequest.new(
...@@ -224,17 +225,19 @@ module Gitlab ...@@ -224,17 +225,19 @@ module Gitlab
) )
request.order = opts[:order].upcase if opts[:order].present? request.order = opts[:order].upcase if opts[:order].present?
response = GitalyClient.call(@repository.storage, :commit_service, :find_all_commits, request, timeout: GitalyClient.medium_timeout) GitalyClient.streaming_call(@repository.storage, :commit_service, :find_all_commits, request, timeout: GitalyClient.medium_timeout) do |response|
consume_commits_response(response) consume_commits_response(response)
end end
end
def list_commits_by_oid(oids) def list_commits_by_oid(oids)
return [] if oids.empty? return [] if oids.empty?
request = Gitaly::ListCommitsByOidRequest.new(repository: @gitaly_repo, oid: oids) request = Gitaly::ListCommitsByOidRequest.new(repository: @gitaly_repo, oid: oids)
response = GitalyClient.call(@repository.storage, :commit_service, :list_commits_by_oid, request, timeout: GitalyClient.medium_timeout) GitalyClient.streaming_call(@repository.storage, :commit_service, :list_commits_by_oid, request, timeout: GitalyClient.medium_timeout) do |response|
consume_commits_response(response) consume_commits_response(response)
end
rescue GRPC::NotFound # If no repository is found, happens mainly during testing rescue GRPC::NotFound # If no repository is found, happens mainly during testing
[] []
end end
...@@ -249,9 +252,10 @@ module Gitlab ...@@ -249,9 +252,10 @@ module Gitlab
offset: offset.to_i offset: offset.to_i
) )
response = GitalyClient.call(@repository.storage, :commit_service, :commits_by_message, request, timeout: GitalyClient.medium_timeout) GitalyClient.streaming_call(@repository.storage, :commit_service, :commits_by_message, request, timeout: GitalyClient.medium_timeout) do |response|
consume_commits_response(response) consume_commits_response(response)
end end
end
def languages(ref = nil) def languages(ref = nil)
request = Gitaly::CommitLanguagesRequest.new(repository: @gitaly_repo, revision: ref || '') request = Gitaly::CommitLanguagesRequest.new(repository: @gitaly_repo, revision: ref || '')
...@@ -323,10 +327,10 @@ module Gitlab ...@@ -323,10 +327,10 @@ module Gitlab
request.paths = encode_repeated(Array(options[:path])) if options[:path].present? request.paths = encode_repeated(Array(options[:path])) if options[:path].present?
response = GitalyClient.call(@repository.storage, :commit_service, :find_commits, request, timeout: GitalyClient.medium_timeout) GitalyClient.streaming_call(@repository.storage, :commit_service, :find_commits, request, timeout: GitalyClient.medium_timeout) do |response|
consume_commits_response(response) consume_commits_response(response)
end end
end
def filter_shas_with_signatures(shas) def filter_shas_with_signatures(shas)
request = Gitaly::FilterShasWithSignaturesRequest.new(repository: @gitaly_repo) request = Gitaly::FilterShasWithSignaturesRequest.new(repository: @gitaly_repo)
......
import * as getters from '~/error_tracking/store/getters';
describe('Error Tracking getters', () => {
let state;
const mockErrors = [
{ title: 'ActiveModel::MissingAttributeError: missing attribute: encrypted_password' },
{ title: 'Grape::Exceptions::MethodNotAllowed: Grape::Exceptions::MethodNotAllowed' },
{ title: 'NoMethodError: undefined method `sanitize_http_headers=' },
{ title: 'NoMethodError: undefined method `pry' },
];
beforeEach(() => {
state = {
errors: mockErrors,
};
});
describe('search results', () => {
it('should return errors filtered by words in title matching the query', () => {
const filteredErrors = getters.filterErrorsByTitle(state)('NoMethod');
expect(filteredErrors).not.toContainEqual(mockErrors[0]);
expect(filteredErrors.length).toBe(2);
});
it('should not return results if there is no matching query', () => {
const filteredErrors = getters.filterErrorsByTitle(state)('GitLab');
expect(filteredErrors.length).toBe(0);
});
});
});
...@@ -377,6 +377,8 @@ describe Gitlab::GitalyClient do ...@@ -377,6 +377,8 @@ describe Gitlab::GitalyClient do
context 'when the request store is active', :request_store do context 'when the request store is active', :request_store do
it 'records call details if a RPC is called' do it 'records call details if a RPC is called' do
expect(described_class).to receive(:measure_timings).and_call_original
gitaly_server.server_version gitaly_server.server_version
expect(described_class.list_call_details).not_to be_empty expect(described_class.list_call_details).not_to be_empty
......
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