Commit 8ceaebc7 authored by Dmitriy Zaporozhets (DZ)'s avatar Dmitriy Zaporozhets (DZ) Committed by Mayra Cabrera

Add GitLab DSN to error tracking UI

parent 5c5d8ad4
<script>
import { GlButton, GlFormGroup, GlFormCheckbox, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
import {
GlButton,
GlFormGroup,
GlFormCheckbox,
GlFormRadioGroup,
GlFormRadio,
GlFormInputGroup,
} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ErrorTrackingForm from './error_tracking_form.vue';
import ProjectDropdown from './project_dropdown.vue';
......@@ -12,7 +20,9 @@ export default {
GlFormGroup,
GlFormRadioGroup,
GlFormRadio,
GlFormInputGroup,
ProjectDropdown,
ClipboardButton,
},
props: {
initialApiHost: {
......@@ -46,6 +56,11 @@ export default {
type: String,
required: true,
},
gitlabDsn: {
type: String,
required: false,
default: null,
},
},
computed: {
...mapGetters([
......@@ -63,6 +78,9 @@ export default {
'settingsLoading',
'token',
]),
showGitlabDsnSetting() {
return this.integrated && this.enabled && this.gitlabDsn;
},
},
created() {
this.setInitialState({
......@@ -119,6 +137,17 @@ export default {
</gl-form-radio>
</gl-form-radio-group>
</gl-form-group>
<gl-form-group
v-if="showGitlabDsnSetting"
:label="__('Paste this DSN into your Sentry SDK')"
data-testid="gitlab-dsn-setting-form"
>
<gl-form-input-group readonly :value="gitlabDsn">
<template #append>
<clipboard-button :text="gitlabDsn" :title="__('Copy')" />
</template>
</gl-form-input-group>
</gl-form-group>
<div v-if="!integrated" class="js-sentry-setting-form" data-testid="sentry-setting-form">
<error-tracking-form />
<div class="form-group">
......
......@@ -13,6 +13,7 @@ export default () => {
token,
listProjectsEndpoint,
operationsSettingsEndpoint,
gitlabDsn,
},
} = formContainerEl;
......@@ -29,6 +30,7 @@ export default () => {
initialToken: token,
listProjectsEndpoint,
operationsSettingsEndpoint,
gitlabDsn,
},
});
},
......
......@@ -46,6 +46,11 @@ module ErrorTracking
after_save :clear_reactive_cache!
# When a user enables the integrated error tracking
# we want to immediately provide them with a first
# working client key so they have a DSN for Sentry SDK.
after_save :create_client_key!
def sentry_enabled
enabled && !integrated_client?
end
......@@ -54,6 +59,12 @@ module ErrorTracking
integrated
end
def gitlab_dsn
strong_memoize(:gitlab_dsn) do
client_key&.sentry_dsn
end
end
def api_url=(value)
super
clear_memoization(:api_url_slugs)
......@@ -236,5 +247,19 @@ module ErrorTracking
errors.add(:project, 'is a required field')
end
end
def client_key
# Project can have multiple client keys.
# However for UI simplicity we render the first active one for user.
# In future we should make it possible to manage client keys from UI.
# Issue https://gitlab.com/gitlab-org/gitlab/-/issues/329596
project.error_tracking_client_keys.active.first
end
def create_client_key!
if enabled? && integrated_client? && !client_key
project.error_tracking_client_keys.create!
end
end
end
end
......@@ -18,4 +18,5 @@
api_host: setting.api_host,
enabled: setting.enabled.to_json,
integrated: setting.integrated.to_json,
gitlab_dsn: setting.gitlab_dsn,
token: setting.token.present? ? '*' * 12 : nil } }
......@@ -24442,6 +24442,9 @@ msgstr ""
msgid "Paste project path (i.e. gitlab-org/gitlab)"
msgstr ""
msgid "Paste this DSN into your Sentry SDK"
msgstr ""
msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
......
......@@ -175,6 +175,12 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
wait_for_requests
assert_text('Your changes have been saved')
within '.js-error-tracking-settings' do
click_button('Expand')
end
expect(page).to have_content('Paste this DSN into your Sentry SDK')
end
end
end
......
import { GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
import { GlFormRadioGroup, GlFormRadio, GlFormInputGroup } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import Vuex from 'vuex';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { TEST_HOST } from 'helpers/test_constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
......@@ -12,6 +13,8 @@ import createStore from '~/error_tracking_settings/store';
const localVue = createLocalVue();
localVue.use(Vuex);
const TEST_GITLAB_DSN = 'https://gitlab.example.com/123456';
describe('error tracking settings app', () => {
let store;
let wrapper;
......@@ -29,6 +32,10 @@ describe('error tracking settings app', () => {
initialProject: null,
listProjectsEndpoint: TEST_HOST,
operationsSettingsEndpoint: TEST_HOST,
gitlabDsn: TEST_GITLAB_DSN,
},
stubs: {
GlFormInputGroup, // we need this non-shallow to query for a component within a slot
},
}),
);
......@@ -41,6 +48,12 @@ describe('error tracking settings app', () => {
findBackendSettingsRadioGroup().findAllComponents(GlFormRadio);
const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text);
const findSentrySettings = () => wrapper.findByTestId('sentry-setting-form');
const findDsnSettings = () => wrapper.findByTestId('gitlab-dsn-setting-form');
const enableGitLabErrorTracking = async () => {
findBackendSettingsRadioGroup().vm.$emit('change', true);
await nextTick();
};
beforeEach(() => {
store = createStore();
......@@ -93,17 +106,35 @@ describe('error tracking settings app', () => {
expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1);
});
it('toggles the sentry-settings section when sentry is selected as a tracking-backend', async () => {
it('hides the Sentry settings when GitLab is selected as a tracking-backend', async () => {
expect(findSentrySettings().exists()).toBe(true);
// set the "integrated" setting to "true"
findBackendSettingsRadioGroup().vm.$emit('change', true);
await nextTick();
await enableGitLabErrorTracking();
expect(findSentrySettings().exists()).toBe(false);
});
describe('GitLab DSN section', () => {
it('is visible when GitLab is selected as a tracking-backend and DSN is present', async () => {
expect(findDsnSettings().exists()).toBe(false);
await enableGitLabErrorTracking();
expect(findDsnSettings().exists()).toBe(true);
});
it('contains copy-to-clipboard functionality for the GitLab DSN string', async () => {
await enableGitLabErrorTracking();
const clipBoardInput = findDsnSettings().findComponent(GlFormInputGroup);
const clipBoardButton = findDsnSettings().findComponent(ClipboardButton);
expect(clipBoardInput.props('value')).toBe(TEST_GITLAB_DSN);
expect(clipBoardInput.attributes('readonly')).toBeTruthy();
expect(clipBoardButton.props('text')).toBe(TEST_GITLAB_DSN);
});
});
it.each([true, false])(
'calls the `updateIntegrated` action when the setting changes to `%s`',
(integrated) => {
......
......@@ -79,6 +79,46 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
end
end
describe 'Callbacks' do
describe 'after_save :create_client_key!' do
subject { build(:project_error_tracking_setting, :integrated, project: project) }
context 'no client key yet' do
it 'creates a new client key' do
expect { subject.save! }.to change { ErrorTracking::ClientKey.count }.by(1)
end
context 'sentry backend' do
before do
subject.integrated = false
end
it 'does not create a new client key' do
expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count }
end
end
context 'feature disabled' do
before do
subject.enabled = false
end
it 'does not create a new client key' do
expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count }
end
end
end
context 'client key already exists' do
let!(:client_key) { create(:error_tracking_client_key, project: project) }
it 'does not create a new client key' do
expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count }
end
end
end
end
describe '.extract_sentry_external_url' do
subject { described_class.extract_sentry_external_url(sentry_url) }
......@@ -494,4 +534,10 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
it { expect(subject.sentry_enabled).to eq(sentry_enabled) }
end
end
describe '#gitlab_dsn' do
let!(:client_key) { create(:error_tracking_client_key, project: project) }
it { expect(subject.gitlab_dsn).to eq(client_key.sentry_dsn) }
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