Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ddaba8dab1
commit
3c7a1efc2f
|
|
@ -491,7 +491,7 @@ lib/gitlab/checks/**
|
|||
/doc/administration/git_protocol.md @msedlakjakubowski
|
||||
/doc/administration/gitaly/ @eread
|
||||
/doc/administration/housekeeping.md @eread
|
||||
/doc/administration/inactive_project_deletion.md @eread
|
||||
/doc/administration/inactive_project_deletion.md @lciutacu
|
||||
/doc/administration/incoming_email.md @msedlakjakubowski
|
||||
/doc/administration/index.md @axil
|
||||
/doc/administration/instance_limits.md @axil
|
||||
|
|
@ -670,7 +670,7 @@ lib/gitlab/checks/**
|
|||
/doc/api/markdown.md @msedlakjakubowski
|
||||
/doc/api/member_roles.md @jglassman1
|
||||
/doc/api/members.md @jglassman1
|
||||
/doc/api/merge_request_approvals.md @msedlakjakubowski
|
||||
/doc/api/merge_request_approvals.md @aqualls
|
||||
/doc/api/merge_request_context_commits.md @aqualls
|
||||
/doc/api/merge_requests.md @aqualls
|
||||
/doc/api/merge_trains.md @marcel.amirault @lyspin
|
||||
|
|
@ -759,9 +759,12 @@ lib/gitlab/checks/**
|
|||
/doc/ci/examples/deployment/ @phillipwells
|
||||
/doc/ci/examples/semantic-release.md @phillipwells
|
||||
/doc/ci/interactive_web_terminal/ @fneill
|
||||
/doc/ci/jobs/ @marcel.amirault
|
||||
/doc/ci/jobs/ci_job_token.md @marcel.amirault
|
||||
/doc/ci/jobs/index.md @marcel.amirault @lyspin
|
||||
/doc/ci/jobs/job_artifacts.md @marcel.amirault
|
||||
/doc/ci/jobs/job_artifacts_troubleshooting.md @marcel.amirault
|
||||
/doc/ci/jobs/job_control.md @marcel.amirault @lyspin
|
||||
/doc/ci/jobs/job_troubleshooting.md @marcel.amirault @lyspin
|
||||
/doc/ci/pipelines/pipeline_security.md @marcel.amirault
|
||||
/doc/ci/resource_groups/ @phillipwells
|
||||
/doc/ci/runners/ @fneill
|
||||
|
|
@ -771,6 +774,7 @@ lib/gitlab/checks/**
|
|||
/doc/ci/ssh_keys/ @marcel.amirault
|
||||
/doc/ci/test_cases/ @msedlakjakubowski
|
||||
/doc/ci/testing/code_quality.md @rdickenson
|
||||
/doc/ci/testing/code_quality_troubleshooting.md @rdickenson
|
||||
/doc/ci/variables/ @marcel.amirault
|
||||
/doc/ci/yaml/signing_examples.md @marcel.amirault
|
||||
/doc/development/advanced_search.md @gitlab-org/search-team/migration-maintainers
|
||||
|
|
@ -779,10 +783,10 @@ lib/gitlab/checks/**
|
|||
/doc/development/avoiding_required_stops.md @gitlab-org/distribution
|
||||
/doc/development/build_test_package.md @gitlab-org/distribution
|
||||
/doc/development/cascading_settings.md @gitlab-org/govern/authentication/approvers
|
||||
/doc/development/cells/ @gitlab-org/tenant-scale-group/backend-engineers
|
||||
/doc/development/cells/ @abdwdd @alexpooley @manojmj
|
||||
/doc/development/cicd/ @gitlab-org/maintainers/cicd-verify
|
||||
/doc/development/contributing/verify/ @gitlab-org/maintainers/cicd-verify
|
||||
/doc/development/database/ @gitlab-org/maintainers/database
|
||||
/doc/development/database/ @abdwdd @alexpooley @manojmj
|
||||
/doc/development/distribution/ @gitlab-org/distribution
|
||||
/doc/development/documentation/ @sselhorn
|
||||
/doc/development/fe_guide/customizable_dashboards.md @gitlab-org/analytics-section/product-analytics/engineers/frontend
|
||||
|
|
@ -792,11 +796,11 @@ lib/gitlab/checks/**
|
|||
/doc/development/gitaly.md @proglottis @toon
|
||||
/doc/development/gitlab_flavored_markdown/ @gitlab-org/maintainers/remote-development/backend @gitlab-org/maintainers/remote-development/frontend
|
||||
/doc/development/gitpod_internals.md @gl-quality/eng-prod
|
||||
/doc/development/image_scaling.md @gitlab-org/tenant-scale-group/backend-engineers
|
||||
/doc/development/image_scaling.md @abdwdd @alexpooley @manojmj
|
||||
/doc/development/internal_analytics/ @gitlab-org/analytics-section/product-analytics/engineers/frontend @gitlab-org/analytics-section/analytics-instrumentation/engineers
|
||||
/doc/development/navigation_sidebar.md @gitlab-org/manage/foundations/engineering
|
||||
/doc/development/omnibus.md @gitlab-org/distribution
|
||||
/doc/development/organization/ @gitlab-org/tenant-scale-group/backend-engineers
|
||||
/doc/development/organization/ @abdwdd @alexpooley @manojmj
|
||||
/doc/development/permissions.md @gitlab-org/govern/authentication/approvers
|
||||
/doc/development/permissions/ @gitlab-org/govern/authentication/approvers
|
||||
/doc/development/permissions/custom_roles.md @gitlab-org/govern/authorization/approvers
|
||||
|
|
@ -855,6 +859,7 @@ lib/gitlab/checks/**
|
|||
/doc/tutorials/dependency_scanning.md @rdickenson
|
||||
/doc/tutorials/export_sbom.md @rdickenson
|
||||
/doc/tutorials/fuzz_testing/ @rdickenson
|
||||
/doc/tutorials/idea_management/ @msedlakjakubowski
|
||||
/doc/tutorials/install_gitlab_single_node/ @axil
|
||||
/doc/tutorials/issue_triage/ @msedlakjakubowski
|
||||
/doc/tutorials/move_personal_project_to_group/ @lciutacu
|
||||
|
|
@ -862,6 +867,7 @@ lib/gitlab/checks/**
|
|||
/doc/tutorials/protected_workflow/ @aqualls
|
||||
/doc/tutorials/scan_execution_policy/ @rdickenson
|
||||
/doc/tutorials/scan_result_policy/ @rdickenson
|
||||
/doc/tutorials/scrum_events/ @msedlakjakubowski
|
||||
/doc/tutorials/update_commit_messages/ @msedlakjakubowski
|
||||
/doc/tutorials/website_project_with_analytics/ @lciutacu
|
||||
/doc/update/ @axil
|
||||
|
|
@ -880,9 +886,11 @@ lib/gitlab/checks/**
|
|||
/doc/user/emoji_reactions.md @msedlakjakubowski
|
||||
/doc/user/enterprise_user/ @jglassman1
|
||||
/doc/user/gitlab_duo_chat.md @sselhorn
|
||||
/doc/user/gitlab_duo_examples.md @sselhorn
|
||||
/doc/user/group/access_and_permissions.md @lciutacu
|
||||
/doc/user/group/clusters/ @phillipwells
|
||||
/doc/user/group/compliance_frameworks.md @eread
|
||||
/doc/user/group/compliance_pipelines.md @eread
|
||||
/doc/user/group/contribution_analytics/ @lciutacu
|
||||
/doc/user/group/custom_project_templates.md @msedlakjakubowski
|
||||
/doc/user/group/devops_adoption/ @lciutacu
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
f508b901207c1e6d2d5bcb8da631b5ad815aa483
|
||||
f68eed8a9d41bfe20840e87c8a9f6cd58db30de3
|
||||
|
|
|
|||
|
|
@ -129,12 +129,16 @@ export default {
|
|||
<div
|
||||
class="filter-dropdown-container gl-md-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-align-items-flex-start"
|
||||
>
|
||||
<toggle-labels />
|
||||
<toggle-epics-swimlanes
|
||||
v-if="swimlanesFeatureAvailable && isSignedIn"
|
||||
:is-swimlanes-on="isSwimlanesOn"
|
||||
@toggleSwimlanes="$emit('toggleSwimlanes', $event)"
|
||||
/>
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-row gl-sm-align-items-flex-start gl-xs-justify-content-end gl-flex-wrap gl-md-flex-nowrap"
|
||||
>
|
||||
<toggle-labels />
|
||||
<toggle-epics-swimlanes
|
||||
v-if="swimlanesFeatureAvailable && isSignedIn"
|
||||
:is-swimlanes-on="isSwimlanesOn"
|
||||
@toggleSwimlanes="$emit('toggleSwimlanes', $event)"
|
||||
/>
|
||||
</div>
|
||||
<config-toggle @showBoardModal="setCurrentForm" />
|
||||
<board-add-new-column-trigger
|
||||
v-if="canAdminList"
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export default {
|
|||
message: __('Failed to load error details from Sentry.'),
|
||||
}),
|
||||
result(res) {
|
||||
if (res.data.project?.sentryErrors?.detailedError) {
|
||||
if (res.data?.project?.sentryErrors?.detailedError) {
|
||||
this.$apollo.queries.error.stopPolling();
|
||||
this.setStatus(this.error.status);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="board-labels-toggle-wrapper gl-display-flex gl-align-items-center gl-ml-3 gl-h-7">
|
||||
<div class="board-labels-toggle-wrapper gl-display-flex gl-align-items-center gl-md-ml-3 gl-h-7">
|
||||
<local-storage-sync
|
||||
:value="isShowingLabels"
|
||||
storage-key="gl-show-board-labels"
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: sidekiq_job_completion_metric_initialize
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64637
|
||||
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1133
|
||||
milestone: '14.1'
|
||||
type: development
|
||||
group: group::scalability
|
||||
default_enabled: true
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: two_factor_for_cli
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39703
|
||||
rollout_issue_url:
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/443750
|
||||
milestone: '13.5'
|
||||
type: development
|
||||
group: group::authentication
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexEnvironmentsNameWithoutType < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.10'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAME = 'index_environments_name_without_type'
|
||||
|
||||
def up
|
||||
add_concurrent_index :environments,
|
||||
"project_id, lower(ltrim(ltrim(name, environment_type), '/')) varchar_pattern_ops, state", name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :environments, INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
f7bdc5bb248a273714916d5426177de7f583e55b17188c858caae37e8e3d617c
|
||||
|
|
@ -24914,6 +24914,8 @@ CREATE INDEX index_environments_cluster_agent_id ON environments USING btree (cl
|
|||
|
||||
CREATE INDEX index_environments_for_name_search_within_folder ON environments USING btree (project_id, lower(ltrim((name)::text, ((environment_type)::text || '/'::text))) varchar_pattern_ops, state);
|
||||
|
||||
CREATE INDEX index_environments_name_without_type ON environments USING btree (project_id, lower(ltrim(ltrim((name)::text, (environment_type)::text), '/'::text)) varchar_pattern_ops, state);
|
||||
|
||||
CREATE INDEX index_environments_on_merge_request_id ON environments USING btree (merge_request_id);
|
||||
|
||||
CREATE INDEX index_environments_on_name_varchar_pattern_ops ON environments USING btree (name varchar_pattern_ops);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: none
|
||||
group: unassigned
|
||||
stage: AI-powered
|
||||
group: AI Framework
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Data Science
|
||||
group: ModelOps
|
||||
stage: ModelOps
|
||||
group: MLOps
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Data Science
|
||||
group: ModelOps
|
||||
stage: ModelOps
|
||||
group: MLOps
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ GitLab can integrate with [Kerberos](https://web.mit.edu/kerberos/) as an authen
|
|||
- You can configure GitLab so your users can sign in with their Kerberos credentials.
|
||||
- You can use Kerberos to [prevent](https://web.mit.edu/sipb/doc/working/guide/guide/node20.html) anyone from intercepting or eavesdropping on the transmitted password.
|
||||
|
||||
Kerberos is only available on instances that use GitLab Enterprise Edition (EE). To use Kerberos, you can do one of the following:
|
||||
|
||||
- [Activate GitLab EE](../administration/license.md#activate-gitlab-ee) for your instance.
|
||||
- If you have set up a GitLab Community Edition (CE) instance using the Linux
|
||||
package, [convert from GitLab CE to GitLab EE](../update/package/convert_to_ee.md).
|
||||
|
||||
WARNING:
|
||||
GitLab CI/CD doesn't work with a Kerberos-enabled GitLab instance unless the integration is
|
||||
[set to use a dedicated port](#http-git-access-with-kerberos-token-passwordless-authentication).
|
||||
|
|
|
|||
|
|
@ -66,8 +66,6 @@ module Gitlab
|
|||
|
||||
metrics[:sidekiq_concurrency].set({}, Sidekiq.default_configuration[:concurrency].to_i)
|
||||
|
||||
return unless ::Feature.enabled?(:sidekiq_job_completion_metric_initialize)
|
||||
|
||||
possible_sli_labels = []
|
||||
::Gitlab::SidekiqConfig.current_worker_queue_mappings.each do |worker, queue|
|
||||
worker_class = worker.safe_constantize
|
||||
|
|
|
|||
|
|
@ -25,16 +25,17 @@ namespace :tw do
|
|||
CodeOwnerRule.new('AI Model Validation', '@sselhorn'),
|
||||
# CodeOwnerRule.new('Analytics Instrumentation', ''),
|
||||
CodeOwnerRule.new('Anti-Abuse', '@phillipwells'),
|
||||
CodeOwnerRule.new('Cloud Connector', '@jglassman1'),
|
||||
CodeOwnerRule.new('Authentication', '@jglassman1'),
|
||||
CodeOwnerRule.new('Authorization', '@jglassman1'),
|
||||
# CodeOwnerRule.new('Billing and Subscription Management', ''),
|
||||
CodeOwnerRule.new('Cloud Connector', '@jglassman1'),
|
||||
CodeOwnerRule.new('Code Creation', '@jglassman1'),
|
||||
CodeOwnerRule.new('Code Review', '@aqualls'),
|
||||
CodeOwnerRule.new('Compliance', '@eread'),
|
||||
CodeOwnerRule.new('Composition Analysis', '@rdickenson'),
|
||||
CodeOwnerRule.new('Container Registry', '@marcel.amirault'),
|
||||
CodeOwnerRule.new('Contributor Experience', '@eread'),
|
||||
CodeOwnerRule.new('Custom Models', '@sselhorn'),
|
||||
# CodeOwnerRule.new('Database', ''),
|
||||
CodeOwnerRule.new('DataOps', '@sselhorn'),
|
||||
# CodeOwnerRule.new('Delivery', ''),
|
||||
|
|
|
|||
|
|
@ -12,8 +12,12 @@ import {
|
|||
} from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Vuex from 'vuex';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import getErrorDetailsQuery from '~/error_tracking/queries/details.query.graphql';
|
||||
import { severityLevel, severityLevelVariant, errorStatus } from '~/error_tracking/constants';
|
||||
import ErrorDetails from '~/error_tracking/components/error_details.vue';
|
||||
import Stacktrace from '~/error_tracking/components/stacktrace.vue';
|
||||
|
|
@ -27,13 +31,61 @@ jest.mock('~/alert');
|
|||
jest.mock('~/tracking');
|
||||
|
||||
Vue.use(Vuex);
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const defaultError = {
|
||||
id: 'gid://gitlab/Gitlab::ErrorTracking::DetailedError/129381',
|
||||
sentryId: 129381,
|
||||
title: 'Issue title',
|
||||
userCount: 2,
|
||||
count: 12,
|
||||
status: 'open',
|
||||
firstSeen: '2017-05-26T13:32:48Z',
|
||||
lastSeen: '2018-05-26T13:32:48Z',
|
||||
message: 'Error',
|
||||
culprit: 'Error',
|
||||
tags: {
|
||||
level: 'high',
|
||||
logger: 'ruby',
|
||||
},
|
||||
externalUrl: 'http://sentry.gitlab.net/gitlab',
|
||||
externalBaseUrl: 'https://gitlab.com',
|
||||
firstReleaseVersion: 1,
|
||||
frequency: null,
|
||||
lastReleaseVersion: 2,
|
||||
gitlabCommit: '12345678',
|
||||
gitlabCommitPath: '/commit/12345678',
|
||||
gitlabIssuePath: '/issues/1',
|
||||
integrated: true,
|
||||
};
|
||||
|
||||
describe('ErrorDetails', () => {
|
||||
let store;
|
||||
let wrapper;
|
||||
let actions;
|
||||
let getters;
|
||||
let mocks;
|
||||
let requestHandlers;
|
||||
|
||||
const mockApolloHandlers = ({ detailedError, getErrorDetailsQueryHandler }) => {
|
||||
return {
|
||||
getErrorDetailsQuery:
|
||||
getErrorDetailsQueryHandler ||
|
||||
jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
id: 1,
|
||||
project: {
|
||||
id: 2,
|
||||
sentryErrors: { id: 3, detailedError: { ...defaultError, ...detailedError } },
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
const createMockApolloProvider = (handlers) => {
|
||||
requestHandlers = handlers;
|
||||
return createMockApollo([[getErrorDetailsQuery, requestHandlers.getErrorDetailsQuery]]);
|
||||
};
|
||||
|
||||
const findInput = (name) => {
|
||||
const inputs = wrapper
|
||||
|
|
@ -48,8 +100,15 @@ describe('ErrorDetails', () => {
|
|||
wrapper.find('[data-testid="update-resolve-status-btn"]');
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
|
||||
function mountComponent({ integratedErrorTrackingEnabled = false } = {}) {
|
||||
const createComponent = async ({
|
||||
integratedErrorTrackingEnabled = false,
|
||||
getErrorDetailsQueryHandler = null,
|
||||
detailedError = {},
|
||||
} = {}) => {
|
||||
wrapper = shallowMount(ErrorDetails, {
|
||||
apolloProvider: createMockApolloProvider(
|
||||
mockApolloHandlers({ detailedError, getErrorDetailsQueryHandler }),
|
||||
),
|
||||
stubs: {
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
|
|
@ -58,7 +117,6 @@ describe('ErrorDetails', () => {
|
|||
GlDisclosureDropdownGroup,
|
||||
},
|
||||
store,
|
||||
mocks,
|
||||
propsData: {
|
||||
issueId: '123',
|
||||
projectPath: '/root/gitlab-test',
|
||||
|
|
@ -70,11 +128,14 @@ describe('ErrorDetails', () => {
|
|||
integratedErrorTrackingEnabled,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await waitForPromises();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
actions = {
|
||||
startPollingStacktrace: () => {},
|
||||
setStatus: jest.fn().mockImplementation(() => {}),
|
||||
startPollingStacktrace: jest.fn().mockImplementation(() => {}),
|
||||
updateIgnoreStatus: jest.fn().mockResolvedValue({}),
|
||||
updateResolveStatus: jest.fn().mockResolvedValue({ closed_issue_iid: 1 }),
|
||||
};
|
||||
|
|
@ -85,7 +146,7 @@ describe('ErrorDetails', () => {
|
|||
};
|
||||
|
||||
const state = {
|
||||
stacktraceData: {},
|
||||
stacktraceData: { date_received: '2020-01-01' },
|
||||
loadingStacktrace: true,
|
||||
errorStatus: '',
|
||||
};
|
||||
|
|
@ -100,28 +161,11 @@ describe('ErrorDetails', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
const query = jest.fn();
|
||||
mocks = {
|
||||
$apollo: {
|
||||
query,
|
||||
queries: {
|
||||
error: {
|
||||
loading: true,
|
||||
stopPolling: jest.fn(),
|
||||
setOptions: jest.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('loading', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('should show spinner while loading', () => {
|
||||
createComponent();
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(GlLink).exists()).toBe(false);
|
||||
expect(wrapper.findComponent(Stacktrace).exists()).toBe(false);
|
||||
|
|
@ -132,76 +176,42 @@ describe('ErrorDetails', () => {
|
|||
const initTime = 300000;
|
||||
const endTime = initTime + 10000;
|
||||
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.queries.error.loading = false;
|
||||
jest.spyOn(Date, 'now').mockReturnValue(initTime);
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('when before timeout, still shows loading', async () => {
|
||||
Date.now.mockReturnValue(endTime - 1);
|
||||
jest
|
||||
.spyOn(Date, 'now')
|
||||
.mockReturnValueOnce(initTime)
|
||||
.mockReturnValueOnce(endTime - 1);
|
||||
|
||||
wrapper.vm.onNoApolloResult();
|
||||
|
||||
await nextTick();
|
||||
await createComponent({ getErrorDetailsQueryHandler: jest.fn().mockRejectedValue({}) });
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||
expect(createAlert).not.toHaveBeenCalled();
|
||||
expect(mocks.$apollo.queries.error.stopPolling).not.toHaveBeenCalled();
|
||||
expect(createAlert).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('when timeout is hit and no apollo result, stops loading and shows alert', async () => {
|
||||
Date.now.mockReturnValue(endTime + 1);
|
||||
|
||||
wrapper.vm.onNoApolloResult();
|
||||
|
||||
await nextTick();
|
||||
jest
|
||||
.spyOn(Date, 'now')
|
||||
.mockReturnValueOnce(initTime)
|
||||
.mockReturnValueOnce(endTime + 1);
|
||||
await createComponent({ getErrorDetailsQueryHandler: jest.fn().mockRejectedValue({}) });
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
|
||||
expect(wrapper.findComponent(GlLink).exists()).toBe(false);
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledTimes(2);
|
||||
expect(createAlert).toHaveBeenLastCalledWith({
|
||||
message: 'Could not connect to Sentry. Refresh the page to try again.',
|
||||
variant: VARIANT_WARNING,
|
||||
});
|
||||
expect(mocks.$apollo.queries.error.stopPolling).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error details', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.queries.error.loading = false;
|
||||
mountComponent();
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
id: 'gid://gitlab/Gitlab::ErrorTracking::DetailedError/129381',
|
||||
sentryId: 129381,
|
||||
title: 'Issue title',
|
||||
externalUrl: 'http://sentry.gitlab.net/gitlab',
|
||||
firstSeen: '2017-05-26T13:32:48Z',
|
||||
lastSeen: '2018-05-26T13:32:48Z',
|
||||
count: 12,
|
||||
userCount: 2,
|
||||
},
|
||||
stacktraceData: {
|
||||
date_received: '2020-05-20',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('unsafe chars for culprit field', () => {
|
||||
const findReportedText = () => wrapper.find('[data-testid="reported-text"]');
|
||||
const culprit = '<script>console.log("surprise!")</script>';
|
||||
beforeEach(() => {
|
||||
|
||||
beforeEach(async () => {
|
||||
store.state.details.loadingStacktrace = false;
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
culprit,
|
||||
},
|
||||
});
|
||||
const detailedError = { culprit };
|
||||
await createComponent({ detailedError });
|
||||
});
|
||||
|
||||
it('should not convert interpolated text to html entities', () => {
|
||||
|
|
@ -216,43 +226,22 @@ describe('ErrorDetails', () => {
|
|||
|
||||
describe('Badges', () => {
|
||||
it('should show language and error level badges', async () => {
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
tags: { level: 'error', logger: 'ruby' },
|
||||
},
|
||||
});
|
||||
await nextTick();
|
||||
const detailedError = { tags: { level: 'error', logger: 'ruby' } };
|
||||
await createComponent({ detailedError });
|
||||
expect(wrapper.findAllComponents(GlBadge).length).toBe(2);
|
||||
});
|
||||
|
||||
it('should NOT show the badge if the tag is not present', async () => {
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
tags: { level: 'error' },
|
||||
},
|
||||
});
|
||||
await nextTick();
|
||||
const detailedError = { tags: { level: 'error', logger: null } };
|
||||
await createComponent({ detailedError });
|
||||
expect(wrapper.findAllComponents(GlBadge).length).toBe(1);
|
||||
});
|
||||
|
||||
it.each(Object.keys(severityLevel))(
|
||||
'should set correct severity level variant for %s badge',
|
||||
async (level) => {
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
tags: { level: severityLevel[level] },
|
||||
},
|
||||
});
|
||||
await nextTick();
|
||||
const detailedError = { tags: { level: severityLevel[level], logger: null } };
|
||||
await createComponent({ detailedError });
|
||||
expect(wrapper.findComponent(GlBadge).props('variant')).toEqual(
|
||||
severityLevelVariant[severityLevel[level]],
|
||||
);
|
||||
|
|
@ -260,15 +249,8 @@ describe('ErrorDetails', () => {
|
|||
);
|
||||
|
||||
it('should fallback for ERROR severityLevelVariant when severityLevel is unknown', async () => {
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
tags: { level: 'someNewErrorLevel' },
|
||||
},
|
||||
});
|
||||
await nextTick();
|
||||
const detailedError = { tags: { level: 'someNewErrorLevel', logger: null } };
|
||||
await createComponent({ detailedError });
|
||||
expect(wrapper.findComponent(GlBadge).props('variant')).toEqual(
|
||||
severityLevelVariant[severityLevel.ERROR],
|
||||
);
|
||||
|
|
@ -277,6 +259,7 @@ describe('ErrorDetails', () => {
|
|||
|
||||
describe('ErrorDetailsInfo', () => {
|
||||
it('should show ErrorDetailsInfo', async () => {
|
||||
await createComponent();
|
||||
store.state.details.loadingStacktrace = false;
|
||||
await nextTick();
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
|
||||
|
|
@ -286,25 +269,19 @@ describe('ErrorDetails', () => {
|
|||
});
|
||||
|
||||
describe('timeline chart', () => {
|
||||
it('should not show timeline chart if frequency data does not exist', () => {
|
||||
it('should not show timeline chart if frequency data does not exist', async () => {
|
||||
await createComponent();
|
||||
expect(wrapper.findComponent(TimelineChart).exists()).toBe(false);
|
||||
expect(wrapper.text()).not.toContain('Last 24 hours');
|
||||
});
|
||||
|
||||
it('should show timeline chart', async () => {
|
||||
const mockFrequency = [
|
||||
[0, 1],
|
||||
[2, 3],
|
||||
{ count: 0, time: 1 },
|
||||
{ count: 2, time: 3 },
|
||||
];
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
frequency: mockFrequency,
|
||||
},
|
||||
});
|
||||
await nextTick();
|
||||
const detailedError = { frequency: mockFrequency };
|
||||
await createComponent({ detailedError });
|
||||
expect(wrapper.findComponent(TimelineChart).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(TimelineChart).props('timelineData')).toEqual(mockFrequency);
|
||||
expect(wrapper.text()).toContain('Last 24 hours');
|
||||
|
|
@ -312,6 +289,10 @@ describe('ErrorDetails', () => {
|
|||
});
|
||||
|
||||
describe('Stacktrace', () => {
|
||||
beforeEach(async () => {
|
||||
await createComponent();
|
||||
});
|
||||
|
||||
it('should show stacktrace', async () => {
|
||||
store.state.details.loadingStacktrace = false;
|
||||
await nextTick();
|
||||
|
|
@ -331,6 +312,10 @@ describe('ErrorDetails', () => {
|
|||
});
|
||||
|
||||
describe('When a user clicks the create issue button', () => {
|
||||
beforeEach(async () => {
|
||||
await createComponent({ detailedError: { gitlabIssuePath: '' } });
|
||||
});
|
||||
|
||||
it('should send sentry_issue_identifier', () => {
|
||||
const sentryErrorIdInput = findInput(
|
||||
'issue[sentry_issue_attributes][sentry_issue_identifier]',
|
||||
|
|
@ -364,8 +349,8 @@ describe('ErrorDetails', () => {
|
|||
|
||||
describe('when error is unresolved', () => {
|
||||
beforeEach(async () => {
|
||||
await createComponent();
|
||||
store.state.details.errorStatus = errorStatus.UNRESOLVED;
|
||||
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
|
|
@ -391,8 +376,8 @@ describe('ErrorDetails', () => {
|
|||
|
||||
describe('when error is ignored', () => {
|
||||
beforeEach(async () => {
|
||||
await createComponent();
|
||||
store.state.details.errorStatus = errorStatus.IGNORED;
|
||||
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
|
|
@ -418,8 +403,8 @@ describe('ErrorDetails', () => {
|
|||
|
||||
describe('when error is resolved', () => {
|
||||
beforeEach(async () => {
|
||||
await createComponent();
|
||||
store.state.details.errorStatus = errorStatus.RESOLVED;
|
||||
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
|
|
@ -443,18 +428,12 @@ describe('ErrorDetails', () => {
|
|||
});
|
||||
|
||||
it('should show alert with closed issueId', async () => {
|
||||
const closedIssueId = 123;
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
isAlertVisible: true,
|
||||
closedIssueId,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
await findUpdateResolveStatusButton().vm.$emit('click');
|
||||
await waitForPromises();
|
||||
expect(findAlert().exists()).toBe(true);
|
||||
expect(findAlert().text()).toContain(`#${closedIssueId}`);
|
||||
expect(findAlert().text()).toBe(
|
||||
'The associated issue #1 has been closed as the error is now resolved.',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -466,15 +445,9 @@ describe('ErrorDetails', () => {
|
|||
const findViewIssueButton = () => wrapper.find('[data-testid="view-issue-button"]');
|
||||
|
||||
describe('is present', () => {
|
||||
beforeEach(() => {
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
gitlabIssuePath,
|
||||
},
|
||||
});
|
||||
beforeEach(async () => {
|
||||
const detailedError = { gitlabIssuePath };
|
||||
await createComponent({ detailedError });
|
||||
});
|
||||
|
||||
it('should display the View issue button', () => {
|
||||
|
|
@ -491,15 +464,9 @@ describe('ErrorDetails', () => {
|
|||
});
|
||||
|
||||
describe('is not present', () => {
|
||||
beforeEach(() => {
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {
|
||||
gitlabIssuePath: null,
|
||||
},
|
||||
});
|
||||
beforeEach(async () => {
|
||||
const detailedError = { gitlabIssuePath: null };
|
||||
await createComponent({ detailedError });
|
||||
});
|
||||
|
||||
it('should not display the View issue button', () => {
|
||||
|
|
@ -518,55 +485,44 @@ describe('ErrorDetails', () => {
|
|||
});
|
||||
|
||||
describe('Snowplow tracking', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.queries.error.loading = false;
|
||||
});
|
||||
|
||||
describe.each([true, false])(`when integratedErrorTracking is %s`, (integrated) => {
|
||||
describe.each`
|
||||
integrated | variant
|
||||
${true} | ${'integrated'}
|
||||
${false} | ${'external'}
|
||||
`(`when integratedErrorTracking is $integrated`, ({ integrated, variant }) => {
|
||||
const category = 'Error Tracking';
|
||||
|
||||
beforeEach(() => {
|
||||
mountComponent({ integratedErrorTrackingEnabled: integrated });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// TODO remove setData usage https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2216
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
error: {},
|
||||
beforeEach(async () => {
|
||||
await createComponent({
|
||||
integratedErrorTrackingEnabled: integrated,
|
||||
detailedError: { gitlabIssuePath: '' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should track detail page views', () => {
|
||||
expect(Tracking.event).toHaveBeenCalledWith(category, 'view_error_details', {
|
||||
extra: {
|
||||
variant: integrated ? 'integrated' : 'external',
|
||||
},
|
||||
extra: { variant },
|
||||
});
|
||||
});
|
||||
|
||||
it('should track IGNORE status update', async () => {
|
||||
await findUpdateIgnoreStatusButton().trigger('click');
|
||||
expect(Tracking.event).toHaveBeenCalledWith(category, 'update_ignored_status', {
|
||||
extra: {
|
||||
variant: integrated ? 'integrated' : 'external',
|
||||
},
|
||||
extra: { variant },
|
||||
});
|
||||
});
|
||||
|
||||
it('should track RESOLVE status update', async () => {
|
||||
await findUpdateResolveStatusButton().trigger('click');
|
||||
expect(Tracking.event).toHaveBeenCalledWith(category, 'update_resolved_status', {
|
||||
extra: {
|
||||
variant: integrated ? 'integrated' : 'external',
|
||||
},
|
||||
extra: { variant },
|
||||
});
|
||||
});
|
||||
|
||||
it('should track create issue button click', async () => {
|
||||
await wrapper.find('[data-testid="create-issue-button"]').vm.$emit('click');
|
||||
expect(Tracking.event).toHaveBeenCalledWith(category, 'click_create_issue_from_error', {
|
||||
extra: {
|
||||
variant: integrated ? 'integrated' : 'external',
|
||||
},
|
||||
extra: { variant },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -72,15 +72,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics, feature_category: :shar
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples "not initializing sidekiq SLIs" do
|
||||
it 'does not initialize sidekiq SLIs' do
|
||||
expect(Gitlab::Metrics::SidekiqSlis)
|
||||
.not_to receive(initialize_sli_method)
|
||||
|
||||
described_class.initialize_process_metrics
|
||||
end
|
||||
end
|
||||
|
||||
context 'initializing execution and queueing SLIs' do
|
||||
before do
|
||||
allow(Gitlab::SidekiqConfig)
|
||||
|
|
@ -115,40 +106,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics, feature_category: :shar
|
|||
described_class.initialize_process_metrics
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the sidekiq_job_completion_metric_initialize feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(sidekiq_job_completion_metric_initialize: false)
|
||||
end
|
||||
|
||||
it 'sets the concurrency metric' do
|
||||
expect(concurrency_metric).to receive(:set).with({}, Sidekiq.default_configuration[:concurrency].to_i)
|
||||
|
||||
described_class.initialize_process_metrics
|
||||
end
|
||||
|
||||
it 'does not initialize sidekiq_jobs_completion_seconds' do
|
||||
allow(Gitlab::SidekiqConfig)
|
||||
.to receive(:current_worker_queue_mappings)
|
||||
.and_return('MergeWorker' => 'merge', 'Ci::BuildFinishedWorker' => 'default')
|
||||
|
||||
expect(completion_seconds_metric).not_to receive(:get)
|
||||
|
||||
described_class.initialize_process_metrics
|
||||
end
|
||||
|
||||
context 'sidekiq execution SLIs' do
|
||||
let(:initialize_sli_method) { :initialize_execution_slis! }
|
||||
|
||||
it_behaves_like 'not initializing sidekiq SLIs'
|
||||
end
|
||||
|
||||
context 'sidekiq queueing SLIs' do
|
||||
let(:initialize_sli_method) { :initialize_queueing_slis! }
|
||||
|
||||
it_behaves_like 'not initializing sidekiq SLIs'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
|
|
|
|||
Loading…
Reference in New Issue