Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
27d1ed4ddf
commit
a7aff3e0e4
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlButton, GlFormGroup, GlFormCheckbox } from '@gitlab/ui';
|
||||
import { GlButton, GlFormGroup, GlFormCheckbox, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import ErrorTrackingForm from './error_tracking_form.vue';
|
||||
import ProjectDropdown from './project_dropdown.vue';
|
||||
|
@ -10,6 +10,8 @@ export default {
|
|||
GlButton,
|
||||
GlFormCheckbox,
|
||||
GlFormGroup,
|
||||
GlFormRadioGroup,
|
||||
GlFormRadio,
|
||||
ProjectDropdown,
|
||||
},
|
||||
props: {
|
||||
|
@ -22,6 +24,10 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
initialIntegrated: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
initialProject: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -49,12 +55,20 @@ export default {
|
|||
'isProjectInvalid',
|
||||
'projectSelectionLabel',
|
||||
]),
|
||||
...mapState(['enabled', 'projects', 'selectedProject', 'settingsLoading', 'token']),
|
||||
...mapState([
|
||||
'enabled',
|
||||
'integrated',
|
||||
'projects',
|
||||
'selectedProject',
|
||||
'settingsLoading',
|
||||
'token',
|
||||
]),
|
||||
},
|
||||
created() {
|
||||
this.setInitialState({
|
||||
apiHost: this.initialApiHost,
|
||||
enabled: this.initialEnabled,
|
||||
integrated: this.initialIntegrated,
|
||||
project: this.initialProject,
|
||||
token: this.initialToken,
|
||||
listProjectsEndpoint: this.listProjectsEndpoint,
|
||||
|
@ -62,7 +76,13 @@ export default {
|
|||
});
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['setInitialState', 'updateEnabled', 'updateSelectedProject', 'updateSettings']),
|
||||
...mapActions([
|
||||
'setInitialState',
|
||||
'updateEnabled',
|
||||
'updateIntegrated',
|
||||
'updateSelectedProject',
|
||||
'updateSettings',
|
||||
]),
|
||||
handleSubmit() {
|
||||
this.updateSettings();
|
||||
},
|
||||
|
@ -76,14 +96,30 @@ export default {
|
|||
:label="s__('ErrorTracking|Enable error tracking')"
|
||||
label-for="error-tracking-enabled"
|
||||
>
|
||||
<gl-form-checkbox
|
||||
id="error-tracking-enabled"
|
||||
:checked="enabled"
|
||||
@change="updateEnabled($event)"
|
||||
>
|
||||
<gl-form-checkbox id="error-tracking-enabled" :checked="enabled" @change="updateEnabled">
|
||||
{{ s__('ErrorTracking|Active') }}
|
||||
</gl-form-checkbox>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
:label="s__('ErrorTracking|Error tracking backend')"
|
||||
data-testid="tracking-backend-settings"
|
||||
>
|
||||
<gl-form-radio-group name="explicit" :checked="integrated" @change="updateIntegrated">
|
||||
<gl-form-radio name="error-tracking-integrated" :value="false">
|
||||
{{ __('Sentry') }}
|
||||
<template #help>
|
||||
{{ __('Requires you to deploy or set up cloud-hosted Sentry.') }}
|
||||
</template>
|
||||
</gl-form-radio>
|
||||
<gl-form-radio name="error-tracking-integrated" :value="true">
|
||||
{{ __('GitLab') }}
|
||||
<template #help>
|
||||
{{ __('Uses GitLab as a lightweight alternative to Sentry.') }}
|
||||
</template>
|
||||
</gl-form-radio>
|
||||
</gl-form-radio-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">
|
||||
<project-dropdown
|
||||
|
@ -98,6 +134,7 @@ export default {
|
|||
@select-project="updateSelectedProject"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<gl-button
|
||||
:disabled="settingsLoading"
|
||||
class="js-error-tracking-button"
|
||||
|
|
|
@ -5,7 +5,15 @@ import createStore from './store';
|
|||
export default () => {
|
||||
const formContainerEl = document.querySelector('.js-error-tracking-form');
|
||||
const {
|
||||
dataset: { apiHost, enabled, project, token, listProjectsEndpoint, operationsSettingsEndpoint },
|
||||
dataset: {
|
||||
apiHost,
|
||||
enabled,
|
||||
integrated,
|
||||
project,
|
||||
token,
|
||||
listProjectsEndpoint,
|
||||
operationsSettingsEndpoint,
|
||||
},
|
||||
} = formContainerEl;
|
||||
|
||||
return new Vue({
|
||||
|
@ -16,6 +24,7 @@ export default () => {
|
|||
props: {
|
||||
initialApiHost: apiHost,
|
||||
initialEnabled: enabled,
|
||||
initialIntegrated: integrated,
|
||||
initialProject: project,
|
||||
initialToken: token,
|
||||
listProjectsEndpoint,
|
||||
|
|
|
@ -79,6 +79,10 @@ export const updateEnabled = ({ commit }, enabled) => {
|
|||
commit(types.UPDATE_ENABLED, enabled);
|
||||
};
|
||||
|
||||
export const updateIntegrated = ({ commit }, integrated) => {
|
||||
commit(types.UPDATE_INTEGRATED, integrated);
|
||||
};
|
||||
|
||||
export const updateToken = ({ commit }, token) => {
|
||||
commit(types.UPDATE_TOKEN, token);
|
||||
commit(types.RESET_CONNECT);
|
||||
|
|
|
@ -6,6 +6,7 @@ export const UPDATE_API_HOST = 'UPDATE_API_HOST';
|
|||
export const UPDATE_CONNECT_ERROR = 'UPDATE_CONNECT_ERROR';
|
||||
export const UPDATE_CONNECT_SUCCESS = 'UPDATE_CONNECT_SUCCESS';
|
||||
export const UPDATE_ENABLED = 'UPDATE_ENABLED';
|
||||
export const UPDATE_INTEGRATED = 'UPDATE_INTEGRATED';
|
||||
export const UPDATE_SELECTED_PROJECT = 'UPDATE_SELECTED_PROJECT';
|
||||
export const UPDATE_SETTINGS_LOADING = 'UPDATE_SETTINGS_LOADING';
|
||||
export const UPDATE_TOKEN = 'UPDATE_TOKEN';
|
||||
|
|
|
@ -20,9 +20,18 @@ export default {
|
|||
},
|
||||
[types.SET_INITIAL_STATE](
|
||||
state,
|
||||
{ apiHost, enabled, project, token, listProjectsEndpoint, operationsSettingsEndpoint },
|
||||
{
|
||||
apiHost,
|
||||
enabled,
|
||||
integrated,
|
||||
project,
|
||||
token,
|
||||
listProjectsEndpoint,
|
||||
operationsSettingsEndpoint,
|
||||
},
|
||||
) {
|
||||
state.enabled = parseBoolean(enabled);
|
||||
state.integrated = parseBoolean(integrated);
|
||||
state.apiHost = apiHost;
|
||||
state.token = token;
|
||||
state.listProjectsEndpoint = listProjectsEndpoint;
|
||||
|
@ -38,6 +47,9 @@ export default {
|
|||
[types.UPDATE_ENABLED](state, enabled) {
|
||||
state.enabled = enabled;
|
||||
},
|
||||
[types.UPDATE_INTEGRATED](state, integrated) {
|
||||
state.integrated = integrated;
|
||||
},
|
||||
[types.UPDATE_TOKEN](state, token) {
|
||||
state.token = token;
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export default () => ({
|
||||
apiHost: '',
|
||||
enabled: false,
|
||||
integrated: false,
|
||||
token: '',
|
||||
projects: [],
|
||||
isLoadingProjects: false,
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
export const projectKeys = ['name', 'organizationName', 'organizationSlug', 'slug'];
|
||||
|
||||
export const transformFrontendSettings = ({ apiHost, enabled, token, selectedProject }) => {
|
||||
export const transformFrontendSettings = ({
|
||||
apiHost,
|
||||
enabled,
|
||||
integrated,
|
||||
token,
|
||||
selectedProject,
|
||||
}) => {
|
||||
const project = selectedProject
|
||||
? {
|
||||
slug: selectedProject.slug,
|
||||
|
@ -10,7 +16,7 @@ export const transformFrontendSettings = ({ apiHost, enabled, token, selectedPro
|
|||
}
|
||||
: null;
|
||||
|
||||
return { api_host: apiHost || null, enabled, token: token || null, project };
|
||||
return { api_host: apiHost || null, enabled, integrated, token: token || null, project };
|
||||
};
|
||||
|
||||
export const getDisplayName = (project) => `${project.organizationName} | ${project.slug}`;
|
||||
|
|
|
@ -136,6 +136,7 @@ module Projects
|
|||
|
||||
error_tracking_setting_attributes: [
|
||||
:enabled,
|
||||
:integrated,
|
||||
:api_host,
|
||||
:token,
|
||||
project: [:slug, :name, :organization_slug, :organization_name]
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SecurityReportsMrWidgetPromptExperiment < ApplicationExperiment # rubocop:disable Gitlab/NamespacedClass
|
||||
def publish(_result = nil)
|
||||
super
|
||||
|
||||
publish_to_database
|
||||
end
|
||||
|
||||
# This is a purely client side experiment, and since we don't have a nicer
|
||||
# way to define variants yet, we define them here.
|
||||
def candidate_behavior
|
||||
end
|
||||
end
|
|
@ -94,6 +94,7 @@ module Projects
|
|||
}
|
||||
}
|
||||
params[:error_tracking_setting_attributes][:token] = settings[:token] unless /\A\*+\z/.match?(settings[:token]) # Don't update token if we receive masked value
|
||||
params[:error_tracking_setting_attributes][:integrated] = settings[:integrated] unless settings[:integrated].nil?
|
||||
|
||||
params
|
||||
end
|
||||
|
|
|
@ -17,4 +17,5 @@
|
|||
project: error_tracking_setting_project_json,
|
||||
api_host: setting.api_host,
|
||||
enabled: setting.enabled.to_json,
|
||||
integrated: setting.integrated.to_json,
|
||||
token: setting.token.present? ? '*' * 12 : nil } }
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/337628
|
|||
milestone: '14.2'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: security_reports_mr_widget_prompt
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70086
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340436
|
||||
milestone: '14.3'
|
||||
type: experiment
|
||||
group: group::adoption
|
||||
default_enabled: false
|
|
@ -7,7 +7,8 @@ product_stage: configure
|
|||
product_group: group::configure
|
||||
product_category: infrastructure_as_code
|
||||
value_type: number
|
||||
status: broken
|
||||
status: removed
|
||||
milestone_removed: '14.3'
|
||||
repair_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332466
|
||||
time_frame: 28d
|
||||
data_source: redis_hll
|
||||
|
|
|
@ -7,7 +7,8 @@ product_stage: configure
|
|||
product_group: group::configure
|
||||
product_category: infrastructure_as_code
|
||||
value_type: number
|
||||
status: broken
|
||||
status: removed
|
||||
milestone_removed: '14.3'
|
||||
repair_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332466
|
||||
time_frame: 7d
|
||||
data_source: redis_hll
|
||||
|
|
|
@ -385,7 +385,6 @@ tables:
|
|||
- public_builds
|
||||
- last_repository_check_failed
|
||||
- last_repository_check_at
|
||||
- container_registry_enabled
|
||||
- only_allow_merge_if_pipeline_succeeds
|
||||
- has_external_issue_tracker
|
||||
- repository_storage
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropTemporaryColumnsAndTriggersForCiBuildNeeds < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
TABLE = 'ci_build_needs'
|
||||
TEMPORARY_COLUMN = 'build_id_convert_to_bigint'
|
||||
MAIN_COLUMN = 'build_id'
|
||||
|
||||
# rubocop:disable Migration/WithLockRetriesDisallowedMethod
|
||||
def up
|
||||
with_lock_retries do
|
||||
cleanup_conversion_of_integer_to_bigint(TABLE, MAIN_COLUMN)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
check_trigger_permissions!(TABLE)
|
||||
|
||||
with_lock_retries do
|
||||
add_column(TABLE, TEMPORARY_COLUMN, :int, default: 0, null: false)
|
||||
install_rename_triggers(TABLE, MAIN_COLUMN, TEMPORARY_COLUMN)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Migration/WithLockRetriesDisallowedMethod
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveContainerRegistryEnabled < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_column :projects, :container_registry_enabled
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
add_column :projects, :container_registry_enabled, :boolean # rubocop:disable Migration/AddColumnsToWideTables
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
c99df310082dd6f5faff3cfd90dfca88af26d840889910ebac0e73ba483a09b2
|
|
@ -0,0 +1 @@
|
|||
abed3f9a6c188890d3dcd21f73a09347f8ccec0f6cc448220fadba5cbda17281
|
|
@ -64,15 +64,6 @@ RETURN NULL;
|
|||
END
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION trigger_21e7a2602957() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
NEW."build_id_convert_to_bigint" := NEW."build_id";
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION trigger_3f6129be01d2() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
|
@ -11227,7 +11218,6 @@ ALTER SEQUENCE chat_teams_id_seq OWNED BY chat_teams.id;
|
|||
|
||||
CREATE TABLE ci_build_needs (
|
||||
id integer NOT NULL,
|
||||
build_id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
||||
name text NOT NULL,
|
||||
artifacts boolean DEFAULT true NOT NULL,
|
||||
optional boolean DEFAULT false NOT NULL,
|
||||
|
@ -18184,7 +18174,6 @@ CREATE TABLE projects (
|
|||
public_builds boolean DEFAULT true NOT NULL,
|
||||
last_repository_check_failed boolean,
|
||||
last_repository_check_at timestamp without time zone,
|
||||
container_registry_enabled boolean,
|
||||
only_allow_merge_if_pipeline_succeeds boolean DEFAULT false NOT NULL,
|
||||
has_external_issue_tracker boolean,
|
||||
repository_storage character varying DEFAULT 'default'::character varying NOT NULL,
|
||||
|
@ -27322,8 +27311,6 @@ ALTER INDEX product_analytics_events_experimental_pkey ATTACH PARTITION gitlab_p
|
|||
|
||||
ALTER INDEX product_analytics_events_experimental_pkey ATTACH PARTITION gitlab_partitions_static.product_analytics_events_experimental_63_pkey;
|
||||
|
||||
CREATE TRIGGER trigger_21e7a2602957 BEFORE INSERT OR UPDATE ON ci_build_needs FOR EACH ROW EXECUTE FUNCTION trigger_21e7a2602957();
|
||||
|
||||
CREATE TRIGGER trigger_3f6129be01d2 BEFORE INSERT OR UPDATE ON ci_builds FOR EACH ROW EXECUTE FUNCTION trigger_3f6129be01d2();
|
||||
|
||||
CREATE TRIGGER trigger_542d6c2ad72e BEFORE INSERT OR UPDATE ON ci_builds_metadata FOR EACH ROW EXECUTE FUNCTION trigger_542d6c2ad72e();
|
||||
|
|
|
@ -265,3 +265,9 @@ by assigning different processes to different parts of the table. The `BATCH`
|
|||
and `UPDATE_DELAY` parameters allow the speed of the migration to be traded off
|
||||
against concurrent access to the table. The `ANSI` parameter should be set to
|
||||
false if your terminal does not support ANSI escape codes.
|
||||
|
||||
By default, `sudo` does not preserve existing environment variables. You should append them, rather than prefix them.
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:external_diffs:force_object_storage START_ID=59946109 END_ID=59946109 UPDATE_DELAY=5
|
||||
```
|
||||
|
|
|
@ -78,7 +78,7 @@ packages on the group level, create a distribution with the same `codename`.
|
|||
To create a project-level distribution:
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions?codename=unstable
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions?codename=unstable"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
|
@ -18,6 +18,24 @@ module Gitlab
|
|||
KNOWN_EVENTS_PATH = File.expand_path('known_events/*.yml', __dir__)
|
||||
ALLOWED_AGGREGATIONS = %i(daily weekly).freeze
|
||||
|
||||
CATEGORIES_FOR_TOTALS = %w[
|
||||
analytics
|
||||
code_review
|
||||
compliance
|
||||
deploy_token_packages
|
||||
ecosystem
|
||||
epic_boards_usage
|
||||
epics_usage
|
||||
ide_edit
|
||||
incident_management
|
||||
issues_edit
|
||||
pipeline_authoring
|
||||
quickactions
|
||||
search
|
||||
testing
|
||||
user_packages
|
||||
].freeze
|
||||
|
||||
# Track event on entity_id
|
||||
# Increment a Redis HLL counter for unique event_name and entity_id
|
||||
#
|
||||
|
@ -90,7 +108,7 @@ module Gitlab
|
|||
hash["#{event}_monthly"] = unique_events(**monthly_time_range.merge(event_names: [event]))
|
||||
end
|
||||
|
||||
if eligible_for_totals?(events_names)
|
||||
if eligible_for_totals?(events_names) && CATEGORIES_FOR_TOTALS.include?(category)
|
||||
event_results["#{category}_total_unique_counts_weekly"] = unique_events(**weekly_time_range.merge(event_names: events_names))
|
||||
event_results["#{category}_total_unique_counts_monthly"] = unique_events(**monthly_time_range.merge(event_names: events_names))
|
||||
end
|
||||
|
|
|
@ -13366,6 +13366,9 @@ msgstr ""
|
|||
msgid "ErrorTracking|Enable error tracking"
|
||||
msgstr ""
|
||||
|
||||
msgid "ErrorTracking|Error tracking backend"
|
||||
msgstr ""
|
||||
|
||||
msgid "ErrorTracking|If you self-host Sentry, enter your Sentry instance's full URL. If you use Sentry's hosted solution, enter https://sentry.io"
|
||||
msgstr ""
|
||||
|
||||
|
@ -28637,6 +28640,9 @@ msgstr[1] ""
|
|||
msgid "Requires values to meet regular expression requirements."
|
||||
msgstr ""
|
||||
|
||||
msgid "Requires you to deploy or set up cloud-hosted Sentry."
|
||||
msgstr ""
|
||||
|
||||
msgid "Requires your primary GitLab email address."
|
||||
msgstr ""
|
||||
|
||||
|
@ -30517,6 +30523,9 @@ msgstr ""
|
|||
msgid "Send service data"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sentry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sentry API URL"
|
||||
msgstr ""
|
||||
|
||||
|
@ -37013,6 +37022,9 @@ msgstr ""
|
|||
msgid "UsersSelect|Unassigned"
|
||||
msgstr ""
|
||||
|
||||
msgid "Uses GitLab as a lightweight alternative to Sentry."
|
||||
msgstr ""
|
||||
|
||||
msgid "Using %{code_start}::%{code_end} denotes a %{link_start}scoped label set%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe SecurityReportsMrWidgetPromptExperiment do
|
||||
it "defines a control and candidate" do
|
||||
expect(subject.behaviors.keys).to match_array(%w[control candidate])
|
||||
end
|
||||
|
||||
it "publishes to the database" do
|
||||
expect(subject).to receive(:publish_to_database)
|
||||
|
||||
subject.publish
|
||||
end
|
||||
end
|
|
@ -89,7 +89,7 @@ RSpec.describe 'Search bar', :js do
|
|||
expect(find('#js-dropdown-hint')).to have_selector('.filter-dropdown .filter-dropdown-item', count: original_size)
|
||||
end
|
||||
|
||||
it 'resets the dropdown filters', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/9985' do
|
||||
it 'resets the dropdown filters' do
|
||||
filtered_search.click
|
||||
|
||||
hint_offset = get_left_style(find('#js-dropdown-hint')['style'])
|
||||
|
@ -103,7 +103,7 @@ RSpec.describe 'Search bar', :js do
|
|||
find('.filtered-search-box .clear-search').click
|
||||
filtered_search.click
|
||||
|
||||
expect(find('#js-dropdown-hint')).to have_selector('.filter-dropdown .filter-dropdown-item', count: 6)
|
||||
expect(find('#js-dropdown-hint')).to have_selector('.filter-dropdown .filter-dropdown-item', minimum: 6)
|
||||
expect(get_left_style(find('#js-dropdown-hint')['style'])).to eq(hint_offset)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -150,6 +150,33 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
|
|||
assert_text('Connection failed. Check Auth Token and try again.')
|
||||
end
|
||||
end
|
||||
|
||||
context 'integrated error tracking backend' do
|
||||
it 'successfully fills and submits the form' do
|
||||
visit project_settings_operations_path(project)
|
||||
|
||||
wait_for_requests
|
||||
|
||||
within '.js-error-tracking-settings' do
|
||||
click_button('Expand')
|
||||
end
|
||||
|
||||
expect(page).to have_content('Error tracking backend')
|
||||
|
||||
within '.js-error-tracking-settings' do
|
||||
check('Active')
|
||||
choose('GitLab')
|
||||
end
|
||||
|
||||
expect(page).not_to have_content('Sentry API URL')
|
||||
|
||||
click_button('Save changes')
|
||||
|
||||
wait_for_requests
|
||||
|
||||
assert_text('Your changes have been saved')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'grafana integration settings form' do
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
|
||||
import ErrorTrackingForm from '~/error_tracking_settings/components/error_tracking_form.vue';
|
||||
import ProjectDropdown from '~/error_tracking_settings/components/project_dropdown.vue';
|
||||
|
@ -14,20 +17,31 @@ describe('error tracking settings app', () => {
|
|||
let wrapper;
|
||||
|
||||
function mountComponent() {
|
||||
wrapper = shallowMount(ErrorTrackingSettings, {
|
||||
wrapper = extendedWrapper(
|
||||
shallowMount(ErrorTrackingSettings, {
|
||||
localVue,
|
||||
store, // Override the imported store
|
||||
propsData: {
|
||||
initialEnabled: 'true',
|
||||
initialIntegrated: 'false',
|
||||
initialApiHost: TEST_HOST,
|
||||
initialToken: 'someToken',
|
||||
initialProject: null,
|
||||
listProjectsEndpoint: TEST_HOST,
|
||||
operationsSettingsEndpoint: TEST_HOST,
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const findBackendSettingsSection = () => wrapper.findByTestId('tracking-backend-settings');
|
||||
const findBackendSettingsRadioGroup = () =>
|
||||
findBackendSettingsSection().findComponent(GlFormRadioGroup);
|
||||
const findBackendSettingsRadioButtons = () =>
|
||||
findBackendSettingsRadioGroup().findAllComponents(GlFormRadio);
|
||||
const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text);
|
||||
const findSentrySettings = () => wrapper.findByTestId('sentry-setting-form');
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore();
|
||||
|
||||
|
@ -62,4 +76,46 @@ describe('error tracking settings app', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tracking-backend settings', () => {
|
||||
it('contains a form-group with the correct label', () => {
|
||||
expect(findBackendSettingsSection().attributes('label')).toBe('Error tracking backend');
|
||||
});
|
||||
|
||||
it('contains a radio group', () => {
|
||||
expect(findBackendSettingsRadioGroup().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('contains the correct radio buttons', () => {
|
||||
expect(findBackendSettingsRadioButtons()).toHaveLength(2);
|
||||
|
||||
expect(findElementWithText(findBackendSettingsRadioButtons(), 'Sentry')).toHaveLength(1);
|
||||
expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('toggles the sentry-settings section when sentry 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();
|
||||
|
||||
expect(findSentrySettings().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it.each([true, false])(
|
||||
'calls the `updateIntegrated` action when the setting changes to `%s`',
|
||||
(integrated) => {
|
||||
jest.spyOn(store, 'dispatch').mockImplementation();
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledTimes(0);
|
||||
|
||||
findBackendSettingsRadioGroup().vm.$emit('change', integrated);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledTimes(1);
|
||||
expect(store.dispatch).toHaveBeenCalledWith('updateIntegrated', integrated);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -42,6 +42,7 @@ export const sampleBackendProject = {
|
|||
export const sampleFrontendSettings = {
|
||||
apiHost: 'apiHost',
|
||||
enabled: false,
|
||||
integrated: false,
|
||||
token: 'token',
|
||||
selectedProject: {
|
||||
slug: normalizedProject.slug,
|
||||
|
@ -54,6 +55,7 @@ export const sampleFrontendSettings = {
|
|||
export const transformedSettings = {
|
||||
api_host: 'apiHost',
|
||||
enabled: false,
|
||||
integrated: false,
|
||||
token: 'token',
|
||||
project: {
|
||||
slug: normalizedProject.slug,
|
||||
|
@ -71,6 +73,7 @@ export const defaultProps = {
|
|||
export const initialEmptyState = {
|
||||
apiHost: '',
|
||||
enabled: false,
|
||||
integrated: false,
|
||||
project: null,
|
||||
token: '',
|
||||
listProjectsEndpoint: TEST_HOST,
|
||||
|
@ -80,6 +83,7 @@ export const initialEmptyState = {
|
|||
export const initialPopulatedState = {
|
||||
apiHost: 'apiHost',
|
||||
enabled: true,
|
||||
integrated: true,
|
||||
project: JSON.stringify(projectList[0]),
|
||||
token: 'token',
|
||||
listProjectsEndpoint: TEST_HOST,
|
||||
|
|
|
@ -202,5 +202,11 @@ describe('error tracking settings actions', () => {
|
|||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it.each([true, false])('should set the `integrated` flag to `%s`', async (payload) => {
|
||||
await testAction(actions.updateIntegrated, payload, state, [
|
||||
{ type: types.UPDATE_INTEGRATED, payload },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,6 +25,7 @@ describe('error tracking settings mutations', () => {
|
|||
|
||||
expect(state.apiHost).toEqual('');
|
||||
expect(state.enabled).toEqual(false);
|
||||
expect(state.integrated).toEqual(false);
|
||||
expect(state.selectedProject).toEqual(null);
|
||||
expect(state.token).toEqual('');
|
||||
expect(state.listProjectsEndpoint).toEqual(TEST_HOST);
|
||||
|
@ -38,6 +39,7 @@ describe('error tracking settings mutations', () => {
|
|||
|
||||
expect(state.apiHost).toEqual('apiHost');
|
||||
expect(state.enabled).toEqual(true);
|
||||
expect(state.integrated).toEqual(true);
|
||||
expect(state.selectedProject).toEqual(projectList[0]);
|
||||
expect(state.token).toEqual('token');
|
||||
expect(state.listProjectsEndpoint).toEqual(TEST_HOST);
|
||||
|
@ -78,5 +80,11 @@ describe('error tracking settings mutations', () => {
|
|||
expect(state.connectSuccessful).toBe(false);
|
||||
expect(state.connectError).toBe(false);
|
||||
});
|
||||
|
||||
it.each([true, false])('should update `integrated` to `%s`', (integrated) => {
|
||||
mutations[types.UPDATE_INTEGRATED](state, integrated);
|
||||
|
||||
expect(state.integrated).toBe(integrated);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,12 +11,14 @@ describe('error tracking settings utils', () => {
|
|||
const emptyFrontendSettingsObject = {
|
||||
apiHost: '',
|
||||
enabled: false,
|
||||
integrated: false,
|
||||
token: '',
|
||||
selectedProject: null,
|
||||
};
|
||||
const transformedEmptySettingsObject = {
|
||||
api_host: null,
|
||||
enabled: false,
|
||||
integrated: false,
|
||||
token: null,
|
||||
project: null,
|
||||
};
|
||||
|
|
|
@ -462,6 +462,8 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
|
|||
allow(described_class).to receive(:known_events).and_return(known_events)
|
||||
allow(described_class).to receive(:categories).and_return(%w(category1 category2))
|
||||
|
||||
stub_const('Gitlab::UsageDataCounters::HLLRedisCounter::CATEGORIES_FOR_TOTALS', %w(category1 category2))
|
||||
|
||||
described_class.track_event('event1_slot', values: entity1, time: 2.days.ago)
|
||||
described_class.track_event('event2_slot', values: entity2, time: 2.days.ago)
|
||||
described_class.track_event('event2_slot', values: entity3, time: 2.weeks.ago)
|
||||
|
|
|
@ -1279,9 +1279,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
|
|||
subject { described_class.redis_hll_counters }
|
||||
|
||||
let(:categories) { ::Gitlab::UsageDataCounters::HLLRedisCounter.categories }
|
||||
let(:ineligible_total_categories) do
|
||||
%w[source_code ci_secrets_management incident_management_alerts snippets terraform incident_management_oncall secure network_policies]
|
||||
end
|
||||
|
||||
context 'with redis_hll_tracking feature enabled' do
|
||||
it 'has all known_events' do
|
||||
|
@ -1296,7 +1293,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
|
|||
|
||||
metrics = keys.map { |key| "#{key}_weekly" } + keys.map { |key| "#{key}_monthly" }
|
||||
|
||||
if ineligible_total_categories.exclude?(category)
|
||||
if ::Gitlab::UsageDataCounters::HLLRedisCounter::CATEGORIES_FOR_TOTALS.include?(category)
|
||||
metrics.append("#{category}_total_unique_counts_weekly", "#{category}_total_unique_counts_monthly")
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!('drop_temporary_columns_and_triggers_for_ci_build_needs')
|
||||
|
||||
RSpec.describe DropTemporaryColumnsAndTriggersForCiBuildNeeds do
|
||||
let(:ci_build_needs_table) { table(:ci_build_needs) }
|
||||
|
||||
it 'correctly migrates up and down' do
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
expect(ci_build_needs_table.column_names).to include('build_id_convert_to_bigint')
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
ci_build_needs_table.reset_column_information
|
||||
expect(ci_build_needs_table.column_names).not_to include('build_id_convert_to_bigint')
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -153,6 +153,7 @@ RSpec.describe Projects::Operations::UpdateService do
|
|||
{
|
||||
error_tracking_setting_attributes: {
|
||||
enabled: false,
|
||||
integrated: true,
|
||||
api_host: 'http://gitlab.com/',
|
||||
token: 'token',
|
||||
project: {
|
||||
|
@ -174,6 +175,7 @@ RSpec.describe Projects::Operations::UpdateService do
|
|||
|
||||
project.reload
|
||||
expect(project.error_tracking_setting).not_to be_enabled
|
||||
expect(project.error_tracking_setting.integrated).to be_truthy
|
||||
expect(project.error_tracking_setting.api_url).to eq(
|
||||
'http://gitlab.com/api/0/projects/org/project/'
|
||||
)
|
||||
|
@ -206,6 +208,7 @@ RSpec.describe Projects::Operations::UpdateService do
|
|||
{
|
||||
error_tracking_setting_attributes: {
|
||||
enabled: true,
|
||||
integrated: true,
|
||||
api_host: 'http://gitlab.com/',
|
||||
token: 'token',
|
||||
project: {
|
||||
|
@ -222,6 +225,7 @@ RSpec.describe Projects::Operations::UpdateService do
|
|||
expect(result[:status]).to eq(:success)
|
||||
|
||||
expect(project.error_tracking_setting).to be_enabled
|
||||
expect(project.error_tracking_setting.integrated).to be_truthy
|
||||
expect(project.error_tracking_setting.api_url).to eq(
|
||||
'http://gitlab.com/api/0/projects/org/project/'
|
||||
)
|
||||
|
|
|
@ -17,25 +17,6 @@ class BareRepoOperations
|
|||
commit_id[0]
|
||||
end
|
||||
|
||||
def commit_file(file, dst_path, branch = 'master')
|
||||
head_id = execute(['show', '--format=format:%H', '--no-patch', branch], allow_failure: true)[0] || Gitlab::Git::EMPTY_TREE_ID
|
||||
|
||||
execute(['read-tree', '--empty'])
|
||||
execute(['read-tree', head_id])
|
||||
|
||||
blob_id = execute(['hash-object', '--stdin', '-w']) do |stdin|
|
||||
stdin.write(file.read)
|
||||
end
|
||||
|
||||
execute(['update-index', '--add', '--cacheinfo', '100644', blob_id[0], dst_path])
|
||||
|
||||
tree_id = execute(['write-tree'])
|
||||
|
||||
commit_id = commit_tree(tree_id[0], "Add #{dst_path}", parent: head_id)
|
||||
|
||||
execute(['update-ref', "refs/heads/#{branch}", commit_id])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def execute(args, allow_failure: false)
|
||||
|
|
Loading…
Reference in New Issue