Commit 81093e5f authored by Dmitriy Zaporozhets (DZ)'s avatar Dmitriy Zaporozhets (DZ) Committed by Jose Ivan Vargas

Improve integrated error tracking issue details

parent c7c495a0
......@@ -128,6 +128,12 @@ export default {
lastReleaseLink() {
return `${this.error.externalBaseUrl}/releases/${this.error.lastReleaseVersion}`;
},
firstCommitLink() {
return `${this.error.externalBaseUrl}/-/commit/${this.error.firstReleaseVersion}`;
},
lastCommitLink() {
return `${this.error.externalBaseUrl}/-/commit/${this.error.lastReleaseVersion}`;
},
showStacktrace() {
return Boolean(this.stacktrace?.length);
},
......@@ -394,7 +400,7 @@ export default {
<span>{{ error.gitlabIssuePath }}</span>
</gl-link>
</li>
<li>
<li v-if="!error.integrated">
<strong class="bold">{{ __('Sentry event') }}:</strong>
<gl-link
v-track-event="trackClickErrorLinkToSentryOptions(error.externalUrl)"
......@@ -409,15 +415,21 @@ export default {
<li v-if="error.firstReleaseVersion">
<strong class="bold">{{ __('First seen') }}:</strong>
<time-ago-tooltip :time="error.firstSeen" />
<gl-link :href="firstReleaseLink" target="_blank">
<span>{{ __('Release') }}: {{ error.firstReleaseVersion }}</span>
<gl-link v-if="error.integrated" :href="firstCommitLink">
{{ __('GitLab commit') }}: {{ error.firstReleaseVersion }}
</gl-link>
<gl-link v-else :href="firstReleaseLink" target="_blank">
{{ __('Release') }}: {{ error.firstReleaseVersion }}
</gl-link>
</li>
<li v-if="error.lastReleaseVersion">
<strong class="bold">{{ __('Last seen') }}:</strong>
<time-ago-tooltip :time="error.lastSeen" />
<gl-link :href="lastReleaseLink" target="_blank">
<span>{{ __('Release') }}: {{ error.lastReleaseVersion }}</span>
<gl-link v-if="error.integrated" :href="lastCommitLink">
{{ __('GitLab commit') }}: {{ error.lastReleaseVersion }}
</gl-link>
<gl-link v-else :href="lastReleaseLink" target="_blank">
{{ __('Release') }}: {{ error.lastReleaseVersion }}
</gl-link>
</li>
<li>
......
......@@ -23,6 +23,7 @@ query errorDetails($fullPath: ID!, $errorId: ID!) {
gitlabCommit
gitlabCommitPath
gitlabIssuePath
integrated
}
}
}
......
......@@ -13,6 +13,9 @@ module Types
field :id, GraphQL::Types::ID,
null: false,
description: 'ID (global ID) of the error.'
field :integrated, GraphQL::Types::Boolean,
null: true,
description: 'Error tracking backend.'
field :sentry_id, GraphQL::Types::String,
method: :id,
null: false,
......
......@@ -7,6 +7,14 @@ class ErrorTracking::Error < ApplicationRecord
has_many :events, class_name: 'ErrorTracking::ErrorEvent'
has_one :first_event,
-> { order(id: :asc) },
class_name: 'ErrorTracking::ErrorEvent'
has_one :last_event,
-> { order(id: :desc) },
class_name: 'ErrorTracking::ErrorEvent'
scope :for_status, -> (status) { where(status: status) }
validates :project, presence: true
......@@ -90,7 +98,10 @@ class ErrorTracking::Error < ApplicationRecord
status: status,
tags: { level: nil, logger: nil },
external_url: external_url,
external_base_url: external_base_url
external_base_url: external_base_url,
integrated: true,
first_release_version: first_event&.release,
last_release_version: last_event&.release
)
end
......@@ -106,6 +117,6 @@ class ErrorTracking::Error < ApplicationRecord
# For compatibility with sentry integration
def external_base_url
Gitlab::Routing.url_helpers.root_url
Gitlab::Routing.url_helpers.project_url(project)
end
end
......@@ -22,6 +22,10 @@ class ErrorTracking::ErrorEvent < ApplicationRecord
)
end
def release
payload.dig('release')
end
private
def build_stacktrace
......
......@@ -13901,6 +13901,7 @@ A Sentry error.
| <a id="sentrydetailederrorgitlabcommitpath"></a>`gitlabCommitPath` | [`String`](#string) | Path to the GitLab page for the GitLab commit attributed to the error. |
| <a id="sentrydetailederrorgitlabissuepath"></a>`gitlabIssuePath` | [`String`](#string) | URL of GitLab Issue. |
| <a id="sentrydetailederrorid"></a>`id` | [`ID!`](#id) | ID (global ID) of the error. |
| <a id="sentrydetailederrorintegrated"></a>`integrated` | [`Boolean`](#boolean) | Error tracking backend. |
| <a id="sentrydetailederrorlastreleaselastcommit"></a>`lastReleaseLastCommit` | [`String`](#string) | Commit the error was last seen. |
| <a id="sentrydetailederrorlastreleaseshortversion"></a>`lastReleaseShortVersion` | [`String`](#string) | Release short version the error was last seen. |
| <a id="sentrydetailederrorlastreleaseversion"></a>`lastReleaseVersion` | [`String`](#string) | Release version the error was last seen. |
......
......@@ -167,7 +167,8 @@ module ErrorTracking
first_release_version: issue.dig('firstRelease', 'version'),
last_release_last_commit: issue.dig('lastRelease', 'lastCommit'),
last_release_short_version: issue.dig('lastRelease', 'shortVersion'),
last_release_version: issue.dig('lastRelease', 'version')
last_release_version: issue.dig('lastRelease', 'version'),
integrated: false
})
end
......
......@@ -22,6 +22,7 @@ module Gitlab
:gitlab_issue,
:gitlab_project,
:id,
:integrated,
:last_release_last_commit,
:last_release_short_version,
:last_release_version,
......
......@@ -503,6 +503,53 @@ describe('ErrorDetails', () => {
});
});
});
describe('Release links', () => {
const firstReleaseVersion = '7975be01';
const firstCommitLink = '/gitlab/-/commit/7975be01';
const firstReleaseLink = '/sentry/releases/7975be01';
const findFirstCommitLink = () => wrapper.find(`[href$="${firstCommitLink}"]`);
const findFirstReleaseLink = () => wrapper.find(`[href$="${firstReleaseLink}"]`);
const lastReleaseVersion = '6ca5a5c1';
const lastCommitLink = '/gitlab/-/commit/6ca5a5c1';
const lastReleaseLink = '/sentry/releases/6ca5a5c1';
const findLastCommitLink = () => wrapper.find(`[href$="${lastCommitLink}"]`);
const findLastReleaseLink = () => wrapper.find(`[href$="${lastReleaseLink}"]`);
it('should display links to Sentry', async () => {
mocks.$apollo.queries.error.loading = false;
await wrapper.setData({
error: {
firstReleaseVersion,
lastReleaseVersion,
externalBaseUrl: '/sentry',
},
});
expect(findFirstReleaseLink().exists()).toBe(true);
expect(findLastReleaseLink().exists()).toBe(true);
expect(findFirstCommitLink().exists()).toBe(false);
expect(findLastCommitLink().exists()).toBe(false);
});
it('should display links to GitLab when integrated', async () => {
mocks.$apollo.queries.error.loading = false;
await wrapper.setData({
error: {
firstReleaseVersion,
lastReleaseVersion,
integrated: true,
externalBaseUrl: '/gitlab',
},
});
expect(findFirstCommitLink().exists()).toBe(true);
expect(findLastCommitLink().exists()).toBe(true);
expect(findFirstReleaseLink().exists()).toBe(false);
expect(findLastReleaseLink().exists()).toBe(false);
});
});
});
describe('Snowplow tracking', () => {
......
......@@ -10,6 +10,7 @@ RSpec.describe GitlabSchema.types['SentryDetailedError'] do
it 'exposes the expected fields' do
expected_fields = %i[
id
integrated
sentryId
title
type
......
......@@ -257,6 +257,10 @@ RSpec.describe ErrorTracking::SentryClient::Issue do
expect(subject.gitlab_issue).to eq('https://gitlab.com/gitlab-org/gitlab/issues/1')
end
it 'has an integrated attribute set to false' do
expect(subject.integrated).to be_falsey
end
context 'when issue annotations exist' do
before do
issue_sample_response['annotations'] = [
......
......@@ -81,6 +81,13 @@ RSpec.describe ErrorTracking::Error, type: :model do
end
describe '#to_sentry_detailed_error' do
it { expect(error.to_sentry_detailed_error).to be_kind_of(Gitlab::ErrorTracking::DetailedError) }
let_it_be(:event) { create(:error_tracking_error_event, error: error) }
subject { error.to_sentry_detailed_error }
it { is_expected.to be_kind_of(Gitlab::ErrorTracking::DetailedError) }
it { expect(subject.integrated).to be_truthy }
it { expect(subject.first_release_version).to eq('db853d7') }
it { expect(subject.last_release_version).to eq('db853d7') }
end
end
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