Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2c6c1c4dce
commit
ea1dcaef18
|
|
@ -182,8 +182,6 @@ Rails/SaveBang:
|
|||
- 'spec/controllers/groups/runners_controller_spec.rb'
|
||||
- 'spec/controllers/groups/uploads_controller_spec.rb'
|
||||
- 'spec/controllers/groups_controller_spec.rb'
|
||||
- 'spec/controllers/oauth/authorizations_controller_spec.rb'
|
||||
- 'spec/controllers/omniauth_callbacks_controller_spec.rb'
|
||||
- 'spec/controllers/profiles/emails_controller_spec.rb'
|
||||
- 'spec/controllers/profiles/notifications_controller_spec.rb'
|
||||
- 'spec/controllers/projects_controller_spec.rb'
|
||||
|
|
@ -197,16 +195,10 @@ Rails/SaveBang:
|
|||
- 'spec/features/admin/admin_sees_project_statistics_spec.rb'
|
||||
- 'spec/features/admin/admin_sees_projects_statistics_spec.rb'
|
||||
- 'spec/features/admin/admin_users_impersonation_tokens_spec.rb'
|
||||
- 'spec/features/boards/sidebar_spec.rb'
|
||||
- 'spec/features/calendar_spec.rb'
|
||||
- 'spec/features/commits_spec.rb'
|
||||
- 'spec/features/dashboard/datetime_on_tooltips_spec.rb'
|
||||
- 'spec/features/dashboard/issuables_counter_spec.rb'
|
||||
- 'spec/features/dashboard/project_member_activity_index_spec.rb'
|
||||
- 'spec/features/dashboard/projects_spec.rb'
|
||||
- 'spec/features/error_tracking/user_sees_error_index_spec.rb'
|
||||
- 'spec/features/groups/members/request_access_spec.rb'
|
||||
- 'spec/features/issuables/close_reopen_report_toggle_spec.rb'
|
||||
- 'spec/features/issues/bulk_assignment_labels_spec.rb'
|
||||
- 'spec/features/issues/gfm_autocomplete_spec.rb'
|
||||
- 'spec/features/issues/issue_sidebar_spec.rb'
|
||||
|
|
@ -217,9 +209,6 @@ Rails/SaveBang:
|
|||
- 'spec/features/issues/user_filters_issues_spec.rb'
|
||||
- 'spec/features/issues/user_sees_live_update_spec.rb'
|
||||
- 'spec/features/issues/user_sorts_issues_spec.rb'
|
||||
- 'spec/features/profiles/emails_spec.rb'
|
||||
- 'spec/features/profiles/password_spec.rb'
|
||||
- 'spec/features/profiles/personal_access_tokens_spec.rb'
|
||||
- 'spec/features/projects/features_visibility_spec.rb'
|
||||
- 'spec/features/projects/fork_spec.rb'
|
||||
- 'spec/features/projects/jobs_spec.rb'
|
||||
|
|
@ -236,12 +225,6 @@ Rails/SaveBang:
|
|||
- 'spec/features/projects/wiki/user_updates_wiki_page_spec.rb'
|
||||
- 'spec/features/projects/wiki/user_views_wiki_page_spec.rb'
|
||||
- 'spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb'
|
||||
- 'spec/features/runners_spec.rb'
|
||||
- 'spec/features/security/project/internal_access_spec.rb'
|
||||
- 'spec/features/security/project/private_access_spec.rb'
|
||||
- 'spec/features/security/project/public_access_spec.rb'
|
||||
- 'spec/features/users/login_spec.rb'
|
||||
- 'spec/features/users/show_spec.rb'
|
||||
- 'spec/frontend/fixtures/issues.rb'
|
||||
- 'spec/frontend/fixtures/merge_requests.rb'
|
||||
- 'spec/graphql/mutations/merge_requests/set_locked_spec.rb'
|
||||
|
|
@ -369,9 +352,6 @@ Rails/SaveBang:
|
|||
- 'spec/models/user_status_spec.rb'
|
||||
- 'spec/models/wiki_page/meta_spec.rb'
|
||||
- 'spec/models/wiki_page_spec.rb'
|
||||
- 'spec/presenters/ci/build_runner_presenter_spec.rb'
|
||||
- 'spec/presenters/ci/trigger_presenter_spec.rb'
|
||||
- 'spec/presenters/packages/conan/package_presenter_spec.rb'
|
||||
- 'spec/requests/api/ci/runner_spec.rb'
|
||||
- 'spec/requests/api/commit_statuses_spec.rb'
|
||||
- 'spec/requests/api/conan_packages_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
79003389aa5098a6ef37e73298cafbad4d9e6b79
|
||||
67a362bf7aaab3aae021d19fda728c24b7723d7a
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import IntegrationForm from '../components/integration_form.vue';
|
|||
import { createStore } from '../stores';
|
||||
|
||||
export default () => {
|
||||
const entryPoint = document.querySelector('#js-cluster-integration-form');
|
||||
const entryPoint = document.querySelector('#js-cluster-details-form');
|
||||
|
||||
if (!entryPoint) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { GlTooltipDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
|
||||
/* eslint-disable vue/no-v-html */
|
||||
import { GlTooltipDirective } from '@gitlab/ui';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
|
@ -21,7 +22,6 @@ export default {
|
|||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
SafeHtml,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
|
|
@ -256,7 +256,7 @@ export default {
|
|||
@mousedown="handleParallelLineMouseDown"
|
||||
>
|
||||
<strong v-if="isLeftConflictMarker">{{ conflictText(line.left) }}</strong>
|
||||
<span v-else v-safe-html="line.left.rich_text"></span>
|
||||
<span v-else v-html="line.left.rich_text"></span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="!inline || (line.left && line.left.type === $options.CONFLICT_MARKER)">
|
||||
|
|
@ -345,7 +345,6 @@ export default {
|
|||
<div
|
||||
:id="line.right.line_code"
|
||||
:key="line.right.rich_text"
|
||||
v-safe-html="line.right.rich_text"
|
||||
:class="[
|
||||
line.right.type,
|
||||
{
|
||||
|
|
@ -360,7 +359,7 @@ export default {
|
|||
<strong v-if="line.right.type === $options.CONFLICT_MARKER_THEIR">{{
|
||||
conflictText(line.right)
|
||||
}}</strong>
|
||||
<span v-else v-safe-html="line.right.rich_text"></span>
|
||||
<span v-else v-html="line.right.rich_text"></span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
|
|
|||
|
|
@ -77,15 +77,10 @@ export default {
|
|||
},
|
||||
|
||||
[types.SET_DIFF_DATA_BATCH](state, data) {
|
||||
const files = prepareDiffData({
|
||||
state.diffFiles = prepareDiffData({
|
||||
diff: data,
|
||||
priorFiles: state.diffFiles,
|
||||
});
|
||||
|
||||
Object.assign(state, {
|
||||
...convertObjectPropsToCamelCase(data),
|
||||
});
|
||||
updateDiffFilesInState(state, files);
|
||||
},
|
||||
|
||||
[types.SET_COVERAGE_DATA](state, coverageFiles) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
<script>
|
||||
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlDropdownSectionHeader } from '@gitlab/ui';
|
||||
import { debounce } from 'lodash';
|
||||
import createFlash from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
const emptyDropdownText = s__('CompareRevisions|Select branch/tag');
|
||||
const EMPTY_DROPDOWN_TEXT = s__('CompareRevisions|Select branch/tag');
|
||||
const SEARCH_DEBOUNCE_MS = 300;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -38,19 +40,11 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
filteredBranches() {
|
||||
return this.branches.filter((branch) =>
|
||||
branch.toLowerCase().includes(this.searchTerm.toLowerCase()),
|
||||
);
|
||||
hasBranches() {
|
||||
return Boolean(this.branches?.length);
|
||||
},
|
||||
hasFilteredBranches() {
|
||||
return this.filteredBranches.length;
|
||||
},
|
||||
filteredTags() {
|
||||
return this.tags.filter((tag) => tag.toLowerCase().includes(this.searchTerm.toLowerCase()));
|
||||
},
|
||||
hasFilteredTags() {
|
||||
return this.filteredTags.length;
|
||||
hasTags() {
|
||||
return Boolean(this.tags?.length);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -59,13 +53,34 @@ export default {
|
|||
this.fetchBranchesAndTags(true);
|
||||
}
|
||||
},
|
||||
searchTerm: debounce(function debounceSearch() {
|
||||
this.searchBranchesAndTags();
|
||||
}, SEARCH_DEBOUNCE_MS),
|
||||
},
|
||||
mounted() {
|
||||
this.fetchBranchesAndTags();
|
||||
},
|
||||
methods: {
|
||||
searchBranchesAndTags() {
|
||||
return axios
|
||||
.get(this.refsProjectPath, {
|
||||
params: {
|
||||
search: this.searchTerm,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.branches = data.Branches || [];
|
||||
this.tags = data.Tags || [];
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({
|
||||
message: s__(
|
||||
'CompareRevisions|There was an error while searching the branch/tag list. Please try again.',
|
||||
),
|
||||
});
|
||||
});
|
||||
},
|
||||
fetchBranchesAndTags(reset = false) {
|
||||
const endpoint = this.refsProjectPath;
|
||||
this.loading = true;
|
||||
|
||||
if (reset) {
|
||||
|
|
@ -73,7 +88,7 @@ export default {
|
|||
}
|
||||
|
||||
return axios
|
||||
.get(endpoint)
|
||||
.get(this.refsProjectPath)
|
||||
.then(({ data }) => {
|
||||
this.branches = data.Branches || [];
|
||||
this.tags = data.Tags || [];
|
||||
|
|
@ -90,7 +105,7 @@ export default {
|
|||
});
|
||||
},
|
||||
getDefaultBranch() {
|
||||
return this.paramsBranch || emptyDropdownText;
|
||||
return this.paramsBranch || EMPTY_DROPDOWN_TEXT;
|
||||
},
|
||||
onClick(revision) {
|
||||
this.selectedRevision = revision;
|
||||
|
|
@ -119,24 +134,24 @@ export default {
|
|||
@keyup.enter="onSearchEnter"
|
||||
/>
|
||||
</template>
|
||||
<gl-dropdown-section-header v-if="hasFilteredBranches">
|
||||
<gl-dropdown-section-header v-if="hasBranches">
|
||||
{{ s__('CompareRevisions|Branches') }}
|
||||
</gl-dropdown-section-header>
|
||||
<gl-dropdown-item
|
||||
v-for="(branch, index) in filteredBranches"
|
||||
:key="`branch${index}`"
|
||||
v-for="branch in branches"
|
||||
:key="branch"
|
||||
is-check-item
|
||||
:is-checked="selectedRevision === branch"
|
||||
@click="onClick(branch)"
|
||||
>
|
||||
{{ branch }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-section-header v-if="hasFilteredTags">
|
||||
<gl-dropdown-section-header v-if="hasTags">
|
||||
{{ s__('CompareRevisions|Tags') }}
|
||||
</gl-dropdown-section-header>
|
||||
<gl-dropdown-item
|
||||
v-for="(tag, index) in filteredTags"
|
||||
:key="`tag${index}`"
|
||||
v-for="tag in tags"
|
||||
:key="tag"
|
||||
is-check-item
|
||||
:is-checked="selectedRevision === tag"
|
||||
@click="onClick(tag)"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
<script>
|
||||
import { GlButton, GlLoadingIcon, GlTooltipDirective, GlIcon } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import ApplySuggestion from './apply_suggestion.vue';
|
||||
|
||||
export default {
|
||||
components: { GlIcon, GlButton, GlLoadingIcon, ApplySuggestion },
|
||||
directives: { 'gl-tooltip': GlTooltipDirective },
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
batchSuggestionsCount: {
|
||||
type: Number,
|
||||
|
|
@ -59,9 +57,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
canBeBatched() {
|
||||
return Boolean(this.glFeatures.batchSuggestions);
|
||||
},
|
||||
isApplying() {
|
||||
return this.isApplyingSingle || this.isApplyingBatch;
|
||||
},
|
||||
|
|
@ -118,7 +113,7 @@ export default {
|
|||
<gl-loading-icon class="d-flex-center mr-2" />
|
||||
<span>{{ applyingSuggestionsMessage }}</span>
|
||||
</div>
|
||||
<div v-else-if="canApply && canBeBatched && isBatched" class="d-flex align-items-center">
|
||||
<div v-else-if="canApply && isBatched" class="d-flex align-items-center">
|
||||
<gl-button
|
||||
class="btn-inverted js-remove-from-batch-btn btn-grouped"
|
||||
:disabled="isApplying"
|
||||
|
|
@ -142,7 +137,7 @@ export default {
|
|||
</div>
|
||||
<div v-else class="d-flex align-items-center">
|
||||
<gl-button
|
||||
v-if="suggestionsCount > 1 && canBeBatched && !isDisableButton"
|
||||
v-if="suggestionsCount > 1 && !isDisableButton"
|
||||
class="btn-inverted js-add-to-batch-btn btn-grouped"
|
||||
data-qa-selector="add_suggestion_batch_button"
|
||||
:disabled="isDisableButton"
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ module RunnerSetupScripts
|
|||
|
||||
private
|
||||
|
||||
def private_runner_setup_scripts(**kwargs)
|
||||
instructions = Gitlab::Ci::RunnerInstructions.new(current_user: current_user, os: script_params[:os], arch: script_params[:arch], **kwargs)
|
||||
def private_runner_setup_scripts
|
||||
instructions = Gitlab::Ci::RunnerInstructions.new(os: script_params[:os], arch: script_params[:arch])
|
||||
output = {
|
||||
install: instructions.install_script,
|
||||
register: instructions.register_command
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ module Groups
|
|||
end
|
||||
|
||||
def runner_setup_scripts
|
||||
private_runner_setup_scripts(group: group)
|
||||
private_runner_setup_scripts
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
|
||||
before_action only: [:show] do
|
||||
push_frontend_feature_flag(:file_identifier_hash)
|
||||
push_frontend_feature_flag(:batch_suggestions, @project, default_enabled: true)
|
||||
push_frontend_feature_flag(:approvals_commented_by, @project, default_enabled: true)
|
||||
push_frontend_feature_flag(:merge_request_widget_graphql, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:drag_comment_selection, @project, default_enabled: true)
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ module Projects
|
|||
end
|
||||
|
||||
def runner_setup_scripts
|
||||
private_runner_setup_scripts(project: @project)
|
||||
private_runner_setup_scripts
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ module Resolvers
|
|||
argument :project_id,
|
||||
type: ::Types::GlobalIDType[::Project],
|
||||
required: false,
|
||||
deprecated: { reason: 'No longer used', milestone: '13.11' },
|
||||
description: 'Project to register the runner for.'
|
||||
|
||||
argument :group_id,
|
||||
type: ::Types::GlobalIDType[::Group],
|
||||
required: false,
|
||||
deprecated: { reason: 'No longer used', milestone: '13.11' },
|
||||
description: 'Group to register the runner for.'
|
||||
|
||||
def resolve(platform:, architecture:, **args)
|
||||
instructions = Gitlab::Ci::RunnerInstructions.new(
|
||||
current_user: current_user,
|
||||
os: platform,
|
||||
arch: architecture,
|
||||
**target_param(args)
|
||||
arch: architecture
|
||||
)
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ class JenkinsService < CiService
|
|||
end
|
||||
|
||||
def execute(data)
|
||||
return if project.disabled_services.include?(to_param)
|
||||
return unless supported_events.include?(data[:object_kind])
|
||||
|
||||
service_hook.execute(data, "#{data[:object_kind]}_hook")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
= form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'js-cluster-integration-form' } do |field|
|
||||
= form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'js-cluster-details-form' } do |field|
|
||||
= form_errors(@cluster)
|
||||
#js-cluster-integration-form{ data: js_cluster_form_data(@cluster, can?(current_user, :update_cluster, @cluster)) }
|
||||
#js-cluster-details-form{ data: js_cluster_form_data(@cluster, can?(current_user, :update_cluster, @cluster)) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix issue where merge description not showing when merged with merge train
|
||||
merge_request: 57787
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove batch_suggestions feature flag
|
||||
merge_request: 57745
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Use search param in refs call to filter revisions
|
||||
merge_request: 57442
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove groupId and projectId arguments to Runner install instructions
|
||||
merge_request: 57720
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Rails/SaveBang Rubocop offenses for presenters
|
||||
merge_request: 57888
|
||||
author: Huzaifa Iftikhar @huzaifaiftikhar
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Rails/SaveBang rubocop offenses in auth controllers
|
||||
merge_request: 57886
|
||||
author: Abdul Wadood @abdulwd
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Rails/SaveBang rubocop offenses in spec/features/
|
||||
merge_request: 57907
|
||||
author: Abdul Wadood @abdulwd
|
||||
type: fixed
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: batch_suggestions
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34782
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/320755
|
||||
milestone: '13.1'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: true
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: sentry_processors_before_send
|
||||
introduced_by_url:
|
||||
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/849#processors
|
||||
milestone: '13.11'
|
||||
type: development
|
||||
group: team::Scalability
|
||||
default_enabled: false
|
||||
|
|
@ -281,9 +281,9 @@ Returns [`RunnerSetup`](#runnersetup).
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| `architecture` | [`String!`](#string) | Architecture to generate the instructions for. |
|
||||
| `groupId` | [`GroupID`](#groupid) | Group to register the runner for. |
|
||||
| `groupId` | [`GroupID`](#groupid) | Group to register the runner for. Deprecated in 13.11: No longer used. |
|
||||
| `platform` | [`String!`](#string) | Platform to generate the instructions for. |
|
||||
| `projectId` | [`ProjectID`](#projectid) | Project to register the runner for. |
|
||||
| `projectId` | [`ProjectID`](#projectid) | Project to register the runner for. Deprecated in 13.11: No longer used. |
|
||||
|
||||
### `snippets`
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Monthly release process
|
||||
|
||||
When a new GitLab version is released on the 22nd, we need to release the published documentation
|
||||
for the new version.
|
||||
When a new GitLab version is released on the 22nd, we release version-specific published
|
||||
documentation for the new version.
|
||||
|
||||
This should be done as soon as possible after the GitLab version is announced, so that:
|
||||
We complete the process as soon as possible after the GitLab version is announced. The result is:
|
||||
|
||||
- The published documentation includes the three most recent minor releases of the current major
|
||||
version, and the most recent minor releases of the last two major versions. For example 13.9,
|
||||
13.8, 13.7, 12.10, and 11.11.
|
||||
- The [online published documentation](https://docs.gitlab.com) includes:
|
||||
- The three most recent minor releases of the current major version. For example 13.9, 13.8, and
|
||||
13.7.
|
||||
- The most recent minor releases of the last two major versions. For example 12.10, and 11.11.
|
||||
- Documentation updates after the 22nd are for the next release. The versions drop down
|
||||
should have the current milestone with `-pre` appended to it, for example `13.10-pre`.
|
||||
|
||||
|
|
@ -31,23 +32,30 @@ For example:
|
|||
[stable branch](https://gitlab.com/gitlab-org/gitlab-docs/-/tree/13.8) and Docker image:
|
||||
[`registry.gitlab.com/gitlab-org/gitlab-docs:13.8`](https://gitlab.com/gitlab-org/gitlab-docs/container_registry/631635).
|
||||
|
||||
To set up a documentation release, follow these steps:
|
||||
## Recommended timeline
|
||||
|
||||
1. [Add the charts version](#add-chart-version), so that the documentation is built using the
|
||||
[version of the charts project that maps to](https://docs.gitlab.com/charts/installation/version_mappings.html)
|
||||
the GitLab release. This step may have been completed already.
|
||||
1. [Create a stable branch and Docker image](#create-stable-branch-and-docker-image-for-release) for
|
||||
the new version.
|
||||
1. [Create a release merge request](#create-release-merge-request) for the new version, which
|
||||
updates the version dropdown menu for the current documentation and adds the release to the
|
||||
Docker configuration. For example, the
|
||||
[release merge request for 13.9](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1555).
|
||||
1. [Update the three online versions](#update-dropdown-for-online-versions), so that they display the new release on their
|
||||
version dropdown menus. For example:
|
||||
- The merge request to [update the 13.9 version dropdown menu for the 13.9 release](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1556).
|
||||
- The merge request to [update the 13.8 version dropdown menu for the 13.9 release](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1557).
|
||||
- The merge request to [update the 13.7 version dropdown menu for the 13.9 release](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1558).
|
||||
1. [Merge the release merge request and run the necessary Docker image builds](#merge-release-merge-request-and-run-docker-image-builds).
|
||||
To minimize problems during the documentation release process, use the following timeline:
|
||||
|
||||
- Before the 20nd of the month:
|
||||
|
||||
[Add the charts version](#add-chart-version), so that the documentation is built using the
|
||||
[version of the charts project that maps to](https://docs.gitlab.com/charts/installation/version_mappings.html)
|
||||
the GitLab release. This step may have been completed already.
|
||||
|
||||
- On or near the 20th of the month:
|
||||
|
||||
1. [Create a stable branch and Docker image](#create-stable-branch-and-docker-image-for-release) for
|
||||
the new version.
|
||||
1. [Create a release merge request](#create-release-merge-request) for the new version, which
|
||||
updates the version dropdown menu for the current documentation and adds the release to the
|
||||
Docker configuration. For example, the
|
||||
[release merge request for 13.9](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1555).
|
||||
1. [Update the three online versions](#update-dropdown-for-online-versions), so that they display the new release on their
|
||||
version dropdown menus.
|
||||
|
||||
- On the 22nd of the month:
|
||||
|
||||
[Merge the release merge requests and run the necessary Docker image builds](#merge-merge-requests-and-run-docker-image-builds).
|
||||
|
||||
## Add chart version
|
||||
|
||||
|
|
@ -135,8 +143,12 @@ Do not merge the release merge request yet.
|
|||
|
||||
## Update dropdown for online versions
|
||||
|
||||
To update`content/_data/versions.yaml` for all online versions (stable branches `X.Y` of the
|
||||
`gitlab-docs` project):
|
||||
To update `content/_data/versions.yaml` for all online versions (stable branches `X.Y` of the
|
||||
`gitlab-docs` project). For example:
|
||||
|
||||
- The merge request to [update the 13.9 version dropdown menu for the 13.9 release](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1556).
|
||||
- The merge request to [update the 13.8 version dropdown menu for the 13.9 release](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1557).
|
||||
- The merge request to [update the 13.7 version dropdown menu for the 13.9 release](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/1558).
|
||||
|
||||
1. Run the Rake task that creates all of the necessary merge requests to update the dropdowns. For
|
||||
example, for the 13.9 release:
|
||||
|
|
@ -146,13 +158,12 @@ To update`content/_data/versions.yaml` for all online versions (stable branches
|
|||
./bin/rake release:dropdowns
|
||||
```
|
||||
|
||||
These merge requests are set to automatically merge.
|
||||
|
||||
1. [Visit the merge requests page](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests?label_name%5B%5D=release)
|
||||
to check that their pipelines pass. After all MRs are merged, proceed to the following and final
|
||||
step.
|
||||
to check that their pipelines pass.
|
||||
|
||||
## Merge release merge request and run Docker image builds
|
||||
Do not merge these merge requests yet.
|
||||
|
||||
## Merge merge requests and run Docker image builds
|
||||
|
||||
The merge requests for the dropdowns should now all be merged into their respective stable branches.
|
||||
Each merge triggers a new pipeline for each stable branch. Wait for the stable branch pipelines to
|
||||
|
|
@ -160,7 +171,9 @@ complete, then:
|
|||
|
||||
1. Check the [pipelines page](https://gitlab.com/gitlab-org/gitlab-docs/pipelines)
|
||||
and make sure all stable branches have green pipelines.
|
||||
1. After all the pipelines succeed, merge the [release merge request](#create-release-merge-request).
|
||||
1. After all the pipelines succeed:
|
||||
1. Merge all of the [dropdown merge requests](#update-dropdown-for-online-versions).
|
||||
1. Merge the [release merge request](#create-release-merge-request).
|
||||
1. Finally, run the
|
||||
[`Build docker images weekly` pipeline](https://gitlab.com/gitlab-org/gitlab-docs/pipeline_schedules)
|
||||
that builds the `:latest` and `:archives` Docker images.
|
||||
|
|
|
|||
|
|
@ -625,7 +625,7 @@ This also applies when using links in between translated sentences, otherwise th
|
|||
```haml
|
||||
- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
|
||||
- zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
|
||||
= s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
|
||||
= html_escape(s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}')) % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
|
||||
```
|
||||
|
||||
- In Vue, instead of:
|
||||
|
|
|
|||
|
|
@ -10124,6 +10124,54 @@ Status: `implemented`
|
|||
|
||||
Tiers: `premium`, `ultimate`
|
||||
|
||||
### `redis_hll_counters.epics_usage.g_project_management_users_updating_fixed_epic_due_date_monthly`
|
||||
|
||||
Counts of MAU manually updating fixed due date
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210329043548_g_project_management_users_updating_fixed_epic_due_date_monthly.yml)
|
||||
|
||||
Group: `group::product planning`
|
||||
|
||||
Status: `implemented`
|
||||
|
||||
Tiers: `premium`, `ultimate`
|
||||
|
||||
### `redis_hll_counters.epics_usage.g_project_management_users_updating_fixed_epic_due_date_weekly`
|
||||
|
||||
Counts of WAU manually updating fixed due date
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210329042536_g_project_management_users_updating_fixed_epic_due_date_weekly.yml)
|
||||
|
||||
Group: `group::product planning`
|
||||
|
||||
Status: `implemented`
|
||||
|
||||
Tiers: `premium`, `ultimate`
|
||||
|
||||
### `redis_hll_counters.epics_usage.g_project_management_users_updating_fixed_epic_start_date_monthly`
|
||||
|
||||
Counts of MAU manually updating fixed start date
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210329043509_g_project_management_users_updating_fixed_epic_start_date_monthly.yml)
|
||||
|
||||
Group: `group::product planning`
|
||||
|
||||
Status: `implemented`
|
||||
|
||||
Tiers: `premium`, `ultimate`
|
||||
|
||||
### `redis_hll_counters.epics_usage.g_project_management_users_updating_fixed_epic_start_date_weekly`
|
||||
|
||||
Counts of WAU manually updating fixed start date
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210329043402_g_project_management_users_updating_fixed_epic_start_date_weekly.yml)
|
||||
|
||||
Group: `group::product planning`
|
||||
|
||||
Status: `implemented`
|
||||
|
||||
Tiers: `premium`, `ultimate`
|
||||
|
||||
### `redis_hll_counters.ide_edit.g_edit_by_sfe_monthly`
|
||||
|
||||
Missing description
|
||||
|
|
|
|||
|
|
@ -486,11 +486,9 @@ introduced by [#25381](https://gitlab.com/gitlab-org/gitlab/-/issues/25381).
|
|||
|
||||
### Batch Suggestions
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25486) in GitLab 13.1 as an [alpha feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#alpha).
|
||||
> - Deployed behind a feature flag, disabled by default.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25486) in GitLab 13.1 as an [alpha feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#alpha) behind a feature flag, disabled by default.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/227799) in GitLab 13.2.
|
||||
> - Enabled on GitLab.com.
|
||||
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-batch-suggestions).
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/320755) in GitLab 13.11.
|
||||
|
||||
You can apply multiple suggestions at once to reduce the number of commits added
|
||||
to your branch to address your reviewers' requests.
|
||||
|
|
@ -540,7 +538,7 @@ You can assign an issue to a user who made a comment.
|
|||
|
||||
In the comment, click the **More Actions** menu and click **Assign to commenting user**.
|
||||
|
||||
Click the button again to unassign the commenter.
|
||||
Click the button again to unassign the commenter.
|
||||
|
||||

|
||||
|
||||
|
|
@ -562,24 +560,3 @@ To disable it:
|
|||
```ruby
|
||||
Feature.disable(:confidential_notes)
|
||||
```
|
||||
|
||||
## Enable or disable Batch Suggestions **(FREE SELF)**
|
||||
|
||||
Batch Suggestions is
|
||||
deployed behind a feature flag that is **enabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
|
||||
can opt to disable it for your instance.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
# Instance-wide
|
||||
Feature.enable(:batch_suggestions)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
# Instance-wide
|
||||
Feature.disable(:batch_suggestions)
|
||||
```
|
||||
|
|
|
|||
|
|
@ -18,38 +18,39 @@ and is automatically configured on [GitHub import](../../../integration/github.m
|
|||
|
||||
## Configuration
|
||||
|
||||
### Complete these steps on GitHub
|
||||
|
||||
This integration requires a [GitHub API token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
|
||||
with `repo:status` access granted:
|
||||
with `repo:status` access granted.
|
||||
|
||||
1. Go to your "Personal access tokens" page at <https://github.com/settings/tokens>
|
||||
1. Click "Generate New Token"
|
||||
1. Ensure that `repo:status` is checked and click "Generate token"
|
||||
1. Copy the generated token to use on GitLab
|
||||
Complete these steps on GitHub:
|
||||
|
||||
### Complete these steps on GitLab
|
||||
1. Go to your **Personal access tokens** page at <https://github.com/settings/tokens>.
|
||||
1. Select **Generate new token**.
|
||||
1. Under **Note**, enter a name for the new token.
|
||||
1. Ensure that `repo:status` is checked and select **Generate token**.
|
||||
1. Copy the generated token to use in GitLab.
|
||||
|
||||
1. Navigate to the project you want to configure.
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
|
||||
1. Click "GitHub".
|
||||
Complete these steps in GitLab:
|
||||
|
||||
1. Go to the project you want to configure.
|
||||
1. Go to the [Integrations page](overview.md#accessing-integrations)
|
||||
1. Select **GitHub**.
|
||||
1. Ensure that the **Active** toggle is enabled.
|
||||
1. Paste the token you've generated on GitHub
|
||||
1. Enter the path to your project on GitHub, such as `https://github.com/username/repository`
|
||||
1. Optionally uncheck **Static status check names** checkbox to disable static status check names.
|
||||
1. Save or optionally click "Test Settings".
|
||||
1. Paste the token you generated on GitHub.
|
||||
1. Enter the path to your project on GitHub, such as `https://github.com/username/repository`.
|
||||
1. (Optional) To disable static status check names, clear the **Static status check names** checkbox.
|
||||
1. Select **Save changes** or optionally select **Test settings**.
|
||||
|
||||
Once the integration is configured, see [Pipelines for external pull requests](../../../ci/ci_cd_for_external_repos/#pipelines-for-external-pull-requests)
|
||||
After configuring the integration, see [Pipelines for external pull requests](../../../ci/ci_cd_for_external_repos/#pipelines-for-external-pull-requests)
|
||||
to configure pipelines to run for open pull requests.
|
||||
|
||||
#### Static / dynamic status check names
|
||||
### Static / dynamic status check names
|
||||
|
||||
> - Introduced in GitLab 11.5: using static status check names as opt-in option.
|
||||
> - [In GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/9931), static status check names is default behavior for new projects.
|
||||
|
||||
This makes it possible to mark these status checks as _Required_ on GitHub.
|
||||
With **Static status check names** enabled on the integration page, your
|
||||
GitLab instance host name is appended to a status check name,
|
||||
whereas in case of dynamic status check names, a branch name is appended.
|
||||
This makes it possible to mark these status checks as **Required** on GitHub.
|
||||
|
||||

|
||||
When **Static status check names** is enabled on the integration page, your
|
||||
GitLab instance host name is appended to a status check name.
|
||||
|
||||
When disabled, it uses dynamic status check names and appends the branch name.
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
|
|
@ -127,7 +127,7 @@ module API
|
|||
# as `:tags` are defined as: `has_many :tags, through: :taggings`
|
||||
# N+1 is solved then by using `subject.tags.map(&:name)`
|
||||
# MR describing the solution: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/20555
|
||||
super(projects_relation).preload(:group)
|
||||
super(projects_relation).preload(group: :namespace_settings)
|
||||
.preload(:ci_cd_settings)
|
||||
.preload(:project_setting)
|
||||
.preload(:container_expiration_policy)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module API
|
|||
|
||||
helpers do
|
||||
def authenticate_gitlab_kas_request!
|
||||
unauthorized! unless Gitlab::Kas.verify_api_request(headers)
|
||||
render_api_error!('KAS JWT authentication invalid', 401) unless Gitlab::Kas.verify_api_request(headers)
|
||||
end
|
||||
|
||||
def agent_token
|
||||
|
|
@ -51,7 +51,7 @@ module API
|
|||
end
|
||||
|
||||
def check_agent_token
|
||||
forbidden! unless agent_token
|
||||
unauthorized! unless agent_token
|
||||
|
||||
forbidden! unless Gitlab::Kas.included_in_gitlab_com_rollout?(agent.project)
|
||||
|
||||
|
|
|
|||
|
|
@ -51,10 +51,7 @@ module Gitlab
|
|||
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(current_user:, group: nil, project: nil, os:, arch:)
|
||||
@current_user = current_user
|
||||
@group = group
|
||||
@project = project
|
||||
def initialize(os:, arch:)
|
||||
@os = os
|
||||
@arch = arch
|
||||
@errors = []
|
||||
|
|
@ -77,7 +74,7 @@ module Gitlab
|
|||
server_url = Gitlab::Routing.url_helpers.root_url(only_path: false)
|
||||
runner_executable = environment[:runner_executable]
|
||||
|
||||
"#{runner_executable} register --url #{server_url} --registration-token #{registration_token}"
|
||||
"#{runner_executable} register --url #{server_url} --registration-token $REGISTRATION_TOKEN"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -108,30 +105,6 @@ module Gitlab
|
|||
def get_file(path)
|
||||
File.read(Rails.root.join(path).to_s)
|
||||
end
|
||||
|
||||
def registration_token
|
||||
project_token || group_token || instance_token
|
||||
end
|
||||
|
||||
def project_token
|
||||
return unless @project
|
||||
raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :admin_pipeline, @project)
|
||||
|
||||
'$REGISTRATION_TOKEN'
|
||||
end
|
||||
|
||||
def group_token
|
||||
return unless @group
|
||||
raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :admin_group, @group)
|
||||
|
||||
'$REGISTRATION_TOKEN'
|
||||
end
|
||||
|
||||
def instance_token
|
||||
raise Gitlab::Access::AccessDeniedError unless @current_user&.admin?
|
||||
|
||||
'$REGISTRATION_TOKEN'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ module Gitlab
|
|||
Rack::Timeout::RequestTimeoutException
|
||||
].freeze
|
||||
|
||||
PROCESSORS = [
|
||||
::Gitlab::ErrorTracking::Processor::SidekiqProcessor,
|
||||
::Gitlab::ErrorTracking::Processor::GrpcErrorProcessor,
|
||||
::Gitlab::ErrorTracking::Processor::ContextPayloadProcessor
|
||||
].freeze
|
||||
|
||||
class << self
|
||||
def configure
|
||||
Raven.configure do |config|
|
||||
|
|
@ -97,7 +103,9 @@ module Gitlab
|
|||
inject_context_for_exception(event, hint[:exception])
|
||||
custom_fingerprinting(event, hint[:exception])
|
||||
|
||||
event
|
||||
PROCESSORS.reduce(event) do |processed_event, processor|
|
||||
processor.call(processed_event)
|
||||
end
|
||||
end
|
||||
|
||||
def process_exception(exception, sentry: false, logging: true, extra:)
|
||||
|
|
|
|||
|
|
@ -9,9 +9,21 @@ module Gitlab
|
|||
# integrations are re-implemented and use Gitlab::ErrorTracking, this
|
||||
# processor should be removed.
|
||||
def process(payload)
|
||||
return payload if ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml)
|
||||
|
||||
context_payload = Gitlab::ErrorTracking::ContextPayloadGenerator.generate(nil, {})
|
||||
payload.deep_merge!(context_payload)
|
||||
end
|
||||
|
||||
def self.call(event)
|
||||
return event unless ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml)
|
||||
|
||||
Gitlab::ErrorTracking::ContextPayloadGenerator.generate(nil, {}).each do |key, value|
|
||||
event.public_send(key).deep_merge!(value) # rubocop:disable GitlabSecurity/PublicSend
|
||||
end
|
||||
|
||||
event
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,60 +6,126 @@ module Gitlab
|
|||
class GrpcErrorProcessor < ::Raven::Processor
|
||||
DEBUG_ERROR_STRING_REGEX = RE2('(.*) debug_error_string:(.*)')
|
||||
|
||||
def process(value)
|
||||
process_first_exception_value(value)
|
||||
process_custom_fingerprint(value)
|
||||
def process(payload)
|
||||
return payload if ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml)
|
||||
|
||||
value
|
||||
self.class.process_first_exception_value(payload)
|
||||
self.class.process_custom_fingerprint(payload)
|
||||
|
||||
payload
|
||||
end
|
||||
|
||||
# Sentry can report multiple exceptions in an event. Sanitize
|
||||
# only the first one since that's what is used for grouping.
|
||||
def process_first_exception_value(value)
|
||||
exceptions = value.dig(:exception, :values)
|
||||
class << self
|
||||
def call(event)
|
||||
return event unless ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml)
|
||||
|
||||
return unless exceptions.is_a?(Array)
|
||||
process_first_exception_value(event)
|
||||
process_custom_fingerprint(event)
|
||||
|
||||
entry = exceptions.first
|
||||
event
|
||||
end
|
||||
|
||||
return unless entry.is_a?(Hash)
|
||||
# Sentry can report multiple exceptions in an event. Sanitize
|
||||
# only the first one since that's what is used for grouping.
|
||||
def process_first_exception_value(event_or_payload)
|
||||
exceptions = exceptions(event_or_payload)
|
||||
|
||||
exception_type = entry[:type]
|
||||
raw_message = entry[:value]
|
||||
return unless exceptions.is_a?(Array)
|
||||
|
||||
return unless exception_type&.start_with?('GRPC::')
|
||||
return unless raw_message.present?
|
||||
exception = exceptions.first
|
||||
|
||||
message, debug_str = split_debug_error_string(raw_message)
|
||||
return unless valid_exception?(exception)
|
||||
|
||||
entry[:value] = message if message
|
||||
extra = value[:extra] || {}
|
||||
extra[:grpc_debug_error_string] = debug_str if debug_str
|
||||
end
|
||||
exception_type, raw_message = type_and_value(exception)
|
||||
|
||||
def process_custom_fingerprint(value)
|
||||
fingerprint = value[:fingerprint]
|
||||
return unless exception_type&.start_with?('GRPC::')
|
||||
return unless raw_message.present?
|
||||
|
||||
return value unless custom_grpc_fingerprint?(fingerprint)
|
||||
message, debug_str = split_debug_error_string(raw_message)
|
||||
|
||||
message, _ = split_debug_error_string(fingerprint[1])
|
||||
fingerprint[1] = message if message
|
||||
end
|
||||
set_new_values!(event_or_payload, exception, message, debug_str)
|
||||
end
|
||||
|
||||
private
|
||||
def process_custom_fingerprint(event)
|
||||
fingerprint = fingerprint(event)
|
||||
|
||||
def custom_grpc_fingerprint?(fingerprint)
|
||||
fingerprint.is_a?(Array) && fingerprint.length == 2 && fingerprint[0].start_with?('GRPC::')
|
||||
end
|
||||
return event unless custom_grpc_fingerprint?(fingerprint)
|
||||
|
||||
def split_debug_error_string(message)
|
||||
return unless message
|
||||
message, _ = split_debug_error_string(fingerprint[1])
|
||||
fingerprint[1] = message if message
|
||||
end
|
||||
|
||||
match = DEBUG_ERROR_STRING_REGEX.match(message)
|
||||
private
|
||||
|
||||
return unless match
|
||||
def custom_grpc_fingerprint?(fingerprint)
|
||||
fingerprint.is_a?(Array) && fingerprint.length == 2 && fingerprint[0].start_with?('GRPC::')
|
||||
end
|
||||
|
||||
[match[1], match[2]]
|
||||
def split_debug_error_string(message)
|
||||
return unless message
|
||||
|
||||
match = DEBUG_ERROR_STRING_REGEX.match(message)
|
||||
|
||||
return unless match
|
||||
|
||||
[match[1], match[2]]
|
||||
end
|
||||
|
||||
# The below methods can be removed once we remove the
|
||||
# sentry_processors_before_send feature flag, and we can
|
||||
# assume we always have an Event object
|
||||
def exceptions(event_or_payload)
|
||||
case event_or_payload
|
||||
when Raven::Event
|
||||
# Better in new version, will be event_or_payload.exception.values
|
||||
event_or_payload.instance_variable_get(:@interfaces)[:exception]&.values
|
||||
when Hash
|
||||
event_or_payload.dig(:exception, :values)
|
||||
end
|
||||
end
|
||||
|
||||
def valid_exception?(exception)
|
||||
case exception
|
||||
when Raven::SingleExceptionInterface
|
||||
exception&.value
|
||||
when Hash
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def type_and_value(exception)
|
||||
case exception
|
||||
when Raven::SingleExceptionInterface
|
||||
[exception.type, exception.value]
|
||||
when Hash
|
||||
exception.values_at(:type, :value)
|
||||
end
|
||||
end
|
||||
|
||||
def set_new_values!(event_or_payload, exception, message, debug_str)
|
||||
case event_or_payload
|
||||
when Raven::Event
|
||||
# Worse in new version, no setter! Have to poke at the
|
||||
# instance variable
|
||||
exception.value = message if message
|
||||
event_or_payload.extra[:grpc_debug_error_string] = debug_str if debug_str
|
||||
when Hash
|
||||
exception[:value] = message if message
|
||||
extra = event_or_payload[:extra] || {}
|
||||
extra[:grpc_debug_error_string] = debug_str if debug_str
|
||||
end
|
||||
end
|
||||
|
||||
def fingerprint(event_or_payload)
|
||||
case event_or_payload
|
||||
when Raven::Event
|
||||
event_or_payload.fingerprint
|
||||
when Hash
|
||||
event_or_payload[:fingerprint]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,39 +8,66 @@ module Gitlab
|
|||
class SidekiqProcessor < ::Raven::Processor
|
||||
FILTERED_STRING = '[FILTERED]'
|
||||
|
||||
def self.filter_arguments(args, klass)
|
||||
args.lazy.with_index.map do |arg, i|
|
||||
case arg
|
||||
when Numeric
|
||||
arg
|
||||
else
|
||||
if permitted_arguments_for_worker(klass).include?(i)
|
||||
class << self
|
||||
def filter_arguments(args, klass)
|
||||
args.lazy.with_index.map do |arg, i|
|
||||
case arg
|
||||
when Numeric
|
||||
arg
|
||||
else
|
||||
FILTERED_STRING
|
||||
if permitted_arguments_for_worker(klass).include?(i)
|
||||
arg
|
||||
else
|
||||
FILTERED_STRING
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.permitted_arguments_for_worker(klass)
|
||||
@permitted_arguments_for_worker ||= {}
|
||||
@permitted_arguments_for_worker[klass] ||=
|
||||
begin
|
||||
klass.constantize&.loggable_arguments&.to_set
|
||||
rescue
|
||||
Set.new
|
||||
def permitted_arguments_for_worker(klass)
|
||||
@permitted_arguments_for_worker ||= {}
|
||||
@permitted_arguments_for_worker[klass] ||=
|
||||
begin
|
||||
klass.constantize&.loggable_arguments&.to_set
|
||||
rescue
|
||||
Set.new
|
||||
end
|
||||
end
|
||||
|
||||
def loggable_arguments(args, klass)
|
||||
Gitlab::Utils::LogLimitedArray
|
||||
.log_limited_array(filter_arguments(args, klass))
|
||||
.map(&:to_s)
|
||||
.to_a
|
||||
end
|
||||
|
||||
def call(event)
|
||||
return event unless ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml)
|
||||
|
||||
sidekiq = event&.extra&.dig(:sidekiq)
|
||||
|
||||
return event unless sidekiq
|
||||
|
||||
sidekiq = sidekiq.deep_dup
|
||||
sidekiq.delete(:jobstr)
|
||||
|
||||
# 'args' in this hash => from Gitlab::ErrorTracking.track_*
|
||||
# 'args' in :job => from default error handler
|
||||
job_holder = sidekiq.key?('args') ? sidekiq : sidekiq[:job]
|
||||
|
||||
if job_holder['args']
|
||||
job_holder['args'] = filter_arguments(job_holder['args'], job_holder['class']).to_a
|
||||
end
|
||||
end
|
||||
|
||||
def self.loggable_arguments(args, klass)
|
||||
Gitlab::Utils::LogLimitedArray
|
||||
.log_limited_array(filter_arguments(args, klass))
|
||||
.map(&:to_s)
|
||||
.to_a
|
||||
event.extra[:sidekiq] = sidekiq
|
||||
|
||||
event
|
||||
end
|
||||
end
|
||||
|
||||
def process(value, key = nil)
|
||||
return value if ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml)
|
||||
|
||||
sidekiq = value.dig(:extra, :sidekiq)
|
||||
|
||||
return value unless sidekiq
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
aggregation: daily
|
||||
feature_flag: track_epics_activity
|
||||
|
||||
# epic notes
|
||||
|
||||
- name: g_project_management_users_creating_epic_notes
|
||||
category: epics_usage
|
||||
redis_slot: project_management
|
||||
|
|
@ -39,24 +41,40 @@
|
|||
aggregation: daily
|
||||
feature_flag: track_epics_activity
|
||||
|
||||
# start date events
|
||||
|
||||
- name: g_project_management_users_setting_epic_start_date_as_fixed
|
||||
category: epics_usage
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
feature_flag: track_epics_activity
|
||||
|
||||
- name: g_project_management_users_updating_fixed_epic_start_date
|
||||
category: epics_usage
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
feature_flag: track_epics_activity
|
||||
|
||||
- name: g_project_management_users_setting_epic_start_date_as_inherited
|
||||
category: epics_usage
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
feature_flag: track_epics_activity
|
||||
|
||||
# due date events
|
||||
|
||||
- name: g_project_management_users_setting_epic_due_date_as_fixed
|
||||
category: epics_usage
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
feature_flag: track_epics_activity
|
||||
|
||||
- name: g_project_management_users_updating_fixed_epic_due_date
|
||||
category: epics_usage
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
feature_flag: track_epics_activity
|
||||
|
||||
- name: g_project_management_users_setting_epic_due_date_as_inherited
|
||||
category: epics_usage
|
||||
redis_slot: project_management
|
||||
|
|
|
|||
|
|
@ -7832,6 +7832,9 @@ msgstr ""
|
|||
msgid "CompareRevisions|There was an error while loading the branch/tag list. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14447,6 +14450,24 @@ msgstr ""
|
|||
msgid "Gitea Import"
|
||||
msgstr ""
|
||||
|
||||
msgid "GithubIntegration|Create a %{token_link_start}personal access token%{token_link_end} with %{status_html} access granted and paste it here."
|
||||
msgstr ""
|
||||
|
||||
msgid "GithubIntegration|Obtain statuses for commits and pull requests."
|
||||
msgstr ""
|
||||
|
||||
msgid "GithubIntegration|Repository URL"
|
||||
msgstr ""
|
||||
|
||||
msgid "GithubIntegration|Select this if you want GitHub to mark status checks as \"Required\". %{learn_more_link_start}Learn more%{learn_more_link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "GithubIntegration|Static status check names (optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "GithubIntegration|This requires mirroring your GitHub repository to this project. %{docs_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Gitlab Pages"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -16706,9 +16727,6 @@ msgstr ""
|
|||
msgid "Integrations|This integration, and inheriting projects were reset."
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|This requires mirroring your GitHub repository to this project. %{docs_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|To keep this project going, create a new issue."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -34336,6 +34354,9 @@ msgstr ""
|
|||
msgid "What does this command do?"
|
||||
msgstr ""
|
||||
|
||||
msgid "What is repository mirroring?"
|
||||
msgstr ""
|
||||
|
||||
msgid "What is squashing?"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -136,11 +136,9 @@ postgresql:
|
|||
metrics:
|
||||
enabled: false
|
||||
resources:
|
||||
requests:
|
||||
cpu: 550m
|
||||
cpu: 600m
|
||||
memory: 1000M
|
||||
limits:
|
||||
cpu: 825m
|
||||
cpu: 1300m
|
||||
memory: 1500M
|
||||
prometheus:
|
||||
install: false
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ RSpec.describe Oauth::AuthorizationsController do
|
|||
shared_examples "Implicit grant can't be used in confidential application" do
|
||||
context 'when application is confidential' do
|
||||
before do
|
||||
application.update(confidential: true)
|
||||
application.update!(confidential: true)
|
||||
params[:response_type] = 'token'
|
||||
end
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ RSpec.describe Oauth::AuthorizationsController do
|
|||
end
|
||||
|
||||
it 'deletes session.user_return_to and redirects when skip authorization' do
|
||||
application.update(trusted: true)
|
||||
application.update!(trusted: true)
|
||||
request.session['user_return_to'] = 'http://example.com'
|
||||
|
||||
subject
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
|
|||
let(:extern_uid) { 'my-uid' }
|
||||
|
||||
before do
|
||||
user.update(failed_attempts: User.maximum_attempts.pred)
|
||||
user.update!(failed_attempts: User.maximum_attempts.pred)
|
||||
subject.response = ActionDispatch::Response.new
|
||||
end
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
|
|||
before do
|
||||
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
|
||||
settings = Gitlab::CurrentSettings.current_application_settings
|
||||
settings.update(disabled_oauth_sign_in_sources: [provider.to_s])
|
||||
settings.update!(disabled_oauth_sign_in_sources: [provider.to_s])
|
||||
end
|
||||
|
||||
it 'prevents login via POST' do
|
||||
|
|
@ -299,7 +299,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
|
|||
before do
|
||||
stub_omniauth_setting(enabled: true, auto_link_user: true, allow_single_sign_on: ['atlassian_oauth2'])
|
||||
|
||||
user.destroy
|
||||
user.destroy!
|
||||
end
|
||||
|
||||
it 'denies sign-in if sign-up is enabled, but block_auto_created_users is set' do
|
||||
|
|
@ -381,7 +381,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
|
|||
|
||||
context 'sign up' do
|
||||
before do
|
||||
user.destroy
|
||||
user.destroy!
|
||||
end
|
||||
|
||||
it 'denies login if sign up is enabled, but block_auto_created_users is set' do
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ RSpec.describe 'Contributions Calendar', :js do
|
|||
author_id: user.id
|
||||
}
|
||||
|
||||
Event.create(note_comment_params)
|
||||
Event.create!(note_comment_params)
|
||||
end
|
||||
|
||||
def selected_day_activities(visible: true)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ RSpec.describe 'Clusterable > Show page' do
|
|||
it 'allow the user to set domain', :js do
|
||||
visit cluster_path
|
||||
|
||||
within '.js-cluster-integration-form' do
|
||||
within '.js-cluster-details-form' do
|
||||
fill_in('cluster_base_domain', with: 'test.com')
|
||||
click_on 'Save changes'
|
||||
end
|
||||
|
|
@ -39,7 +39,7 @@ RSpec.describe 'Clusterable > Show page' do
|
|||
end
|
||||
|
||||
it 'shows help text with the domain as an alternative to custom domain', :js do
|
||||
within '.js-cluster-integration-form' do
|
||||
within '.js-cluster-details-form' do
|
||||
expect(find(cluster_ingress_help_text_selector).text).to include('192.168.1.100')
|
||||
end
|
||||
end
|
||||
|
|
@ -49,7 +49,7 @@ RSpec.describe 'Clusterable > Show page' do
|
|||
it 'alternative to custom domain is not shown' do
|
||||
visit cluster_path
|
||||
|
||||
within '.js-cluster-integration-form' do
|
||||
within '.js-cluster-details-form' do
|
||||
expect(page).not_to have_selector(cluster_ingress_help_text_selector)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ RSpec.describe 'Commits' do
|
|||
|
||||
context 'when accessing internal project with disallowed access', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/299575' do
|
||||
before do
|
||||
project.update(
|
||||
project.update!(
|
||||
visibility_level: Gitlab::VisibilityLevel::INTERNAL,
|
||||
public_builds: false)
|
||||
create(:ci_job_artifact, :archive, file: artifacts_file, job: build)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ RSpec.describe 'View error index page', :js, :use_clean_rails_memory_store_cachi
|
|||
|
||||
context 'with error tracking settings disabled' do
|
||||
before do
|
||||
project_error_tracking_settings.update(enabled: false)
|
||||
project_error_tracking_settings.update!(enabled: false)
|
||||
sign_in(project.owner)
|
||||
|
||||
visit project_error_tracking_index_path(project)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ RSpec.describe 'User Cluster', :js do
|
|||
context 'when user disables the cluster' do
|
||||
before do
|
||||
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
|
||||
page.within('.js-cluster-integration-form') { click_button 'Save changes' }
|
||||
page.within('.js-cluster-details-form') { click_button 'Save changes' }
|
||||
end
|
||||
|
||||
it 'user sees the successful message' do
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ RSpec.describe 'Groups > Members > Request access' do
|
|||
end
|
||||
|
||||
it 'request access feature is disabled' do
|
||||
group.update(request_access_enabled: false)
|
||||
group.update!(request_access_enabled: false)
|
||||
visit group_path(group)
|
||||
|
||||
expect(page).not_to have_content 'Request Access'
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ RSpec.describe 'Profile > Emails' do
|
|||
end
|
||||
|
||||
it 'user removes email' do
|
||||
user.emails.create(email: 'my@email.com')
|
||||
user.emails.create!(email: 'my@email.com')
|
||||
visit profile_emails_path
|
||||
expect(page).to have_content("my@email.com")
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ RSpec.describe 'Profile > Emails' do
|
|||
end
|
||||
|
||||
it 'user confirms email' do
|
||||
email = user.emails.create(email: 'my@email.com')
|
||||
email = user.emails.create!(email: 'my@email.com')
|
||||
visit profile_emails_path
|
||||
expect(page).to have_content("#{email.email} Unverified")
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ RSpec.describe 'Profile > Emails' do
|
|||
end
|
||||
|
||||
it 'user re-sends confirmation email' do
|
||||
email = user.emails.create(email: 'my@email.com')
|
||||
email = user.emails.create!(email: 'my@email.com')
|
||||
visit profile_emails_path
|
||||
|
||||
expect { click_link("Resend confirmation email") }.to have_enqueued_job.on_queue('mailers')
|
||||
|
|
@ -72,7 +72,7 @@ RSpec.describe 'Profile > Emails' do
|
|||
end
|
||||
|
||||
it 'old unconfirmed emails show Send Confirmation button' do
|
||||
email = user.emails.create(email: 'my@email.com')
|
||||
email = user.emails.create!(email: 'my@email.com')
|
||||
email.update_attribute(:confirmation_sent_at, nil)
|
||||
visit profile_emails_path
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ RSpec.describe 'Profile > Password' do
|
|||
before do
|
||||
sign_in(user)
|
||||
|
||||
user.update(password_expires_at: 1.hour.ago)
|
||||
user.update!(password_expires_at: 1.hour.ago)
|
||||
user.identities.delete
|
||||
expect(user.ldap_user?).to eq false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
|
|||
end
|
||||
|
||||
it "removes expired tokens from 'active' section" do
|
||||
personal_access_token.update(expires_at: 5.days.ago)
|
||||
personal_access_token.update!(expires_at: 5.days.ago)
|
||||
visit profile_personal_access_tokens_path
|
||||
|
||||
expect(page).to have_selector(".settings-message")
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ RSpec.describe 'Gcp Cluster', :js do
|
|||
context 'when user disables the cluster' do
|
||||
before do
|
||||
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
|
||||
page.within('.js-cluster-integration-form') { click_button 'Save changes' }
|
||||
page.within('.js-cluster-details-form') { click_button 'Save changes' }
|
||||
end
|
||||
|
||||
it 'user sees the successful message' do
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ RSpec.describe 'User Cluster', :js do
|
|||
context 'when user disables the cluster' do
|
||||
before do
|
||||
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
|
||||
page.within('.js-cluster-integration-form') { click_button 'Save changes' }
|
||||
page.within('.js-cluster-details-form') { click_button 'Save changes' }
|
||||
end
|
||||
|
||||
it 'user sees the successful message' do
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ RSpec.describe 'Clusters', :js do
|
|||
before do
|
||||
click_link 'default-cluster'
|
||||
fill_in 'cluster_environment_scope', with: 'production/*'
|
||||
within '.js-cluster-integration-form' do
|
||||
within '.js-cluster-details-form' do
|
||||
click_button 'Save changes'
|
||||
end
|
||||
end
|
||||
|
|
@ -149,7 +149,7 @@ RSpec.describe 'Clusters', :js do
|
|||
before do
|
||||
click_link 'default-cluster'
|
||||
fill_in 'cluster_environment_scope', with: 'production/*'
|
||||
within ".js-cluster-integration-form" do
|
||||
within ".js-cluster-details-form" do
|
||||
click_button 'Save changes'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ RSpec.describe 'Runners' do
|
|||
|
||||
context 'when a runner has a tag' do
|
||||
before do
|
||||
specific_runner.update(tag_list: ['tag'])
|
||||
specific_runner.update!(tag_list: ['tag'])
|
||||
end
|
||||
|
||||
it 'user edits runner not to run untagged jobs' do
|
||||
|
|
@ -370,7 +370,7 @@ RSpec.describe 'Runners' do
|
|||
|
||||
context 'when a runner has a tag' do
|
||||
before do
|
||||
runner.update(tag_list: ['tag'])
|
||||
runner.update!(tag_list: ['tag'])
|
||||
end
|
||||
|
||||
it 'user edits runner not to run untagged jobs' do
|
||||
|
|
@ -450,7 +450,7 @@ RSpec.describe 'Runners' do
|
|||
|
||||
context 'when a runner has a tag' do
|
||||
before do
|
||||
runner.update(tag_list: ['tag'])
|
||||
runner.update!(tag_list: ['tag'])
|
||||
end
|
||||
|
||||
it 'user edits runner not to run untagged jobs' do
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ RSpec.describe "Internal Project Access" do
|
|||
|
||||
context "when allowed for public and internal" do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -372,7 +372,7 @@ RSpec.describe "Internal Project Access" do
|
|||
|
||||
context "when disallowed for public and internal" do
|
||||
before do
|
||||
project.update(public_builds: false)
|
||||
project.update!(public_builds: false)
|
||||
end
|
||||
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -396,7 +396,7 @@ RSpec.describe "Internal Project Access" do
|
|||
|
||||
context "when allowed for public and internal" do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -412,7 +412,7 @@ RSpec.describe "Internal Project Access" do
|
|||
|
||||
context "when disallowed for public and internal" do
|
||||
before do
|
||||
project.update(public_builds: false)
|
||||
project.update!(public_builds: false)
|
||||
end
|
||||
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -436,7 +436,7 @@ RSpec.describe "Internal Project Access" do
|
|||
|
||||
context 'when allowed for public and internal' do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -452,7 +452,7 @@ RSpec.describe "Internal Project Access" do
|
|||
|
||||
context 'when disallowed for public and internal' do
|
||||
before do
|
||||
project.update(public_builds: false)
|
||||
project.update!(public_builds: false)
|
||||
end
|
||||
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ RSpec.describe "Private Project Access" do
|
|||
|
||||
context 'when public builds is enabled' do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:guest).of(project) }
|
||||
|
|
@ -348,7 +348,7 @@ RSpec.describe "Private Project Access" do
|
|||
|
||||
context 'when public builds is enabled' do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:guest).of(project) }
|
||||
|
|
@ -375,7 +375,7 @@ RSpec.describe "Private Project Access" do
|
|||
|
||||
context 'when public builds is enabled' do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:guest).of(project) }
|
||||
|
|
@ -405,7 +405,7 @@ RSpec.describe "Private Project Access" do
|
|||
|
||||
context 'when public builds is enabled' do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:guest).of(project) }
|
||||
|
|
@ -414,7 +414,7 @@ RSpec.describe "Private Project Access" do
|
|||
context 'when public buils are disabled' do
|
||||
before do
|
||||
project.public_builds = false
|
||||
project.save
|
||||
project.save!
|
||||
end
|
||||
|
||||
it { is_expected.to be_denied_for(:guest).of(project) }
|
||||
|
|
@ -440,7 +440,7 @@ RSpec.describe "Private Project Access" do
|
|||
|
||||
context 'when public builds is enabled' do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:guest).of(project) }
|
||||
|
|
@ -448,7 +448,7 @@ RSpec.describe "Private Project Access" do
|
|||
|
||||
context 'when public builds is disabled' do
|
||||
before do
|
||||
project.update(public_builds: false)
|
||||
project.update!(public_builds: false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_denied_for(:guest).of(project) }
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ RSpec.describe "Public Project Access" do
|
|||
|
||||
context "when allowed for public" do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -180,7 +180,7 @@ RSpec.describe "Public Project Access" do
|
|||
|
||||
context "when disallowed for public" do
|
||||
before do
|
||||
project.update(public_builds: false)
|
||||
project.update!(public_builds: false)
|
||||
end
|
||||
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -204,7 +204,7 @@ RSpec.describe "Public Project Access" do
|
|||
|
||||
context "when allowed for public" do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -220,7 +220,7 @@ RSpec.describe "Public Project Access" do
|
|||
|
||||
context "when disallowed for public" do
|
||||
before do
|
||||
project.update(public_builds: false)
|
||||
project.update!(public_builds: false)
|
||||
end
|
||||
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -244,7 +244,7 @@ RSpec.describe "Public Project Access" do
|
|||
|
||||
context 'when allowed for public' do
|
||||
before do
|
||||
project.update(public_builds: true)
|
||||
project.update!(public_builds: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
@ -260,7 +260,7 @@ RSpec.describe "Public Project Access" do
|
|||
|
||||
context 'when disallowed for public' do
|
||||
before do
|
||||
project.update(public_builds: false)
|
||||
project.update!(public_builds: false)
|
||||
end
|
||||
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) }
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ RSpec.describe 'Login' do
|
|||
expect(codes.size).to eq 10
|
||||
|
||||
# Ensure the generated codes get saved
|
||||
user.save(touch: false)
|
||||
user.save!(touch: false)
|
||||
end
|
||||
|
||||
context 'with valid code' do
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ RSpec.describe 'User page' do
|
|||
|
||||
context 'work information' do
|
||||
it 'shows job title and organization details' do
|
||||
user.update(organization: 'GitLab - work info test', job_title: 'Frontend Engineer')
|
||||
user.update!(organization: 'GitLab - work info test', job_title: 'Frontend Engineer')
|
||||
|
||||
subject
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ RSpec.describe 'User page' do
|
|||
end
|
||||
|
||||
it 'shows job title' do
|
||||
user.update(organization: nil, job_title: 'Frontend Engineer - work info test')
|
||||
user.update!(organization: nil, job_title: 'Frontend Engineer - work info test')
|
||||
|
||||
subject
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ RSpec.describe 'User page' do
|
|||
end
|
||||
|
||||
it 'shows organization details' do
|
||||
user.update(organization: 'GitLab - work info test', job_title: '')
|
||||
user.update!(organization: 'GitLab - work info test', job_title: '')
|
||||
|
||||
subject
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlDropdown } from '@gitlab/ui';
|
||||
import { GlDropdown, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import createFlash from '~/flash';
|
||||
|
|
@ -23,6 +23,10 @@ describe('RevisionDropdown component', () => {
|
|||
...defaultProps,
|
||||
...props,
|
||||
},
|
||||
stubs: {
|
||||
GlDropdown,
|
||||
GlSearchBoxByType,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -36,6 +40,7 @@ describe('RevisionDropdown component', () => {
|
|||
});
|
||||
|
||||
const findGlDropdown = () => wrapper.find(GlDropdown);
|
||||
const findSearchBox = () => wrapper.find(GlSearchBoxByType);
|
||||
|
||||
it('sets hidden input', () => {
|
||||
createComponent();
|
||||
|
|
@ -85,6 +90,40 @@ describe('RevisionDropdown component', () => {
|
|||
expect(axios.get).toHaveBeenLastCalledWith(newRefsProjectPath);
|
||||
});
|
||||
|
||||
describe('search', () => {
|
||||
it('shows flash message on error', async () => {
|
||||
axiosMock.onGet('some/invalid/path').replyOnce(404);
|
||||
|
||||
createComponent();
|
||||
|
||||
await wrapper.vm.searchBranchesAndTags();
|
||||
expect(createFlash).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('makes request with search param', async () => {
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: {
|
||||
Branches: [],
|
||||
Tags: [],
|
||||
},
|
||||
});
|
||||
|
||||
const mockSearchTerm = 'foobar';
|
||||
createComponent();
|
||||
findSearchBox().vm.$emit('input', mockSearchTerm);
|
||||
await axios.waitForAll();
|
||||
|
||||
expect(axios.get).toHaveBeenCalledWith(
|
||||
defaultProps.refsProjectPath,
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
search: mockSearchTerm,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GlDropdown component', () => {
|
||||
it('renders props', () => {
|
||||
createComponent();
|
||||
|
|
|
|||
|
|
@ -16,18 +16,12 @@ const DEFAULT_PROPS = {
|
|||
describe('Suggestion Diff component', () => {
|
||||
let wrapper;
|
||||
|
||||
const createComponent = (props, glFeatures = {}) => {
|
||||
const createComponent = (props) => {
|
||||
wrapper = shallowMount(SuggestionDiffHeader, {
|
||||
propsData: {
|
||||
...DEFAULT_PROPS,
|
||||
...props,
|
||||
},
|
||||
provide: {
|
||||
glFeatures: {
|
||||
batchSuggestions: true,
|
||||
...glFeatures,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -211,18 +205,6 @@ describe('Suggestion Diff component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('batchSuggestions feature flag is set to false', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({}, { batchSuggestions: false });
|
||||
});
|
||||
|
||||
it('disables add to batch buttons but keeps apply suggestion enabled', () => {
|
||||
expect(findApplyButton().exists()).toBe(true);
|
||||
expect(findAddToBatchButton().exists()).toBe(false);
|
||||
expect(findApplyButton().attributes('disabled')).not.toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('canApply is set to false', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ canApply: false });
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@ RSpec.describe Resolvers::Ci::RunnerSetupResolver do
|
|||
describe '#resolve' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
subject(:resolve_subject) { resolve(described_class, ctx: { current_user: user }, args: { platform: platform, architecture: 'amd64' }.merge(target_param)) }
|
||||
subject(:resolve_subject) { resolve(described_class, ctx: { current_user: user }, args: { platform: platform, architecture: 'amd64' }) }
|
||||
|
||||
context 'with container platforms' do
|
||||
let(:platform) { 'docker' }
|
||||
let(:project) { create(:project) }
|
||||
let(:target_param) { { project_id: project.to_global_id } }
|
||||
|
||||
it 'returns install instructions' do
|
||||
expect(resolve_subject[:install_instructions]).not_to eq(nil)
|
||||
|
|
@ -27,77 +26,9 @@ RSpec.describe Resolvers::Ci::RunnerSetupResolver do
|
|||
context 'with regular platforms' do
|
||||
let(:platform) { 'linux' }
|
||||
|
||||
context 'without target parameter' do
|
||||
let(:target_param) { {} }
|
||||
|
||||
context 'when user is not admin' do
|
||||
it 'returns access error' do
|
||||
expect { resolve_subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is admin' do
|
||||
before do
|
||||
user.update!(admin: true)
|
||||
end
|
||||
|
||||
it 'returns install and register instructions' do
|
||||
expect(resolve_subject.keys).to contain_exactly(:install_instructions, :register_instructions)
|
||||
expect(resolve_subject.values).not_to include(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with project target parameter' do
|
||||
let(:project) { create(:project) }
|
||||
let(:target_param) { { project_id: project.to_global_id } }
|
||||
|
||||
context 'when user has access to admin builds on project' do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
it 'returns install and register instructions' do
|
||||
expect(resolve_subject.keys).to contain_exactly(:install_instructions, :register_instructions)
|
||||
expect(resolve_subject.values).not_to include(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user does not have access to admin builds on project' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
it 'returns access error' do
|
||||
expect { resolve_subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with group target parameter' do
|
||||
let(:group) { create(:group) }
|
||||
let(:target_param) { { group_id: group.to_global_id } }
|
||||
|
||||
context 'when user has access to admin builds on group' do
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'returns install and register instructions' do
|
||||
expect(resolve_subject.keys).to contain_exactly(:install_instructions, :register_instructions)
|
||||
expect(resolve_subject.values).not_to include(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user does not have access to admin builds on group' do
|
||||
before do
|
||||
group.add_developer(user)
|
||||
end
|
||||
|
||||
it 'returns access error' do
|
||||
expect { resolve_subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
it 'returns install and register instructions' do
|
||||
expect(resolve_subject.keys).to contain_exactly(:install_instructions, :register_instructions)
|
||||
expect(resolve_subject.values).not_to include(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ RSpec.describe Gitlab::Ci::RunnerInstructions do
|
|||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let(:params) { {} }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
describe 'OS' do
|
||||
Gitlab::Ci::RunnerInstructions::OS.each do |name, subject|
|
||||
|
|
@ -37,7 +36,7 @@ RSpec.describe Gitlab::Ci::RunnerInstructions do
|
|||
end
|
||||
|
||||
describe '#install_script' do
|
||||
subject { described_class.new(current_user: user, **params) }
|
||||
subject { described_class.new(**params) }
|
||||
|
||||
context 'invalid params' do
|
||||
where(:current_params, :expected_error_message) do
|
||||
|
|
@ -106,117 +105,18 @@ RSpec.describe Gitlab::Ci::RunnerInstructions do
|
|||
end
|
||||
end
|
||||
|
||||
context 'group' do
|
||||
let(:group) { create(:group) }
|
||||
|
||||
subject { described_class.new(current_user: user, group: group, **params) }
|
||||
|
||||
context 'user is owner' do
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:params) { { os: commands.each_key.first, arch: 'foo' } }
|
||||
|
||||
it 'have correct configurations' do
|
||||
result = subject.register_command
|
||||
|
||||
expect(result).to include("#{commands[commands.each_key.first]} register")
|
||||
expect(result).to include("--registration-token $REGISTRATION_TOKEN")
|
||||
expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'user is not owner' do
|
||||
where(:user_permission) do
|
||||
[:maintainer, :developer, :reporter, :guest]
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
create(:group_member, user_permission, group: group, user: user)
|
||||
end
|
||||
|
||||
it 'raises error' do
|
||||
result = subject.register_command
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'project' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
subject { described_class.new(current_user: user, project: project, **params) }
|
||||
|
||||
context 'user is maintainer' do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:params) { { os: commands.each_key.first, arch: 'foo' } }
|
||||
|
||||
it 'have correct configurations' do
|
||||
result = subject.register_command
|
||||
|
||||
expect(result).to include("#{commands[commands.each_key.first]} register")
|
||||
expect(result).to include("--registration-token $REGISTRATION_TOKEN")
|
||||
expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'user is not maintainer' do
|
||||
where(:user_permission) do
|
||||
[:developer, :reporter, :guest]
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
create(:project_member, user_permission, project: project, user: user)
|
||||
end
|
||||
|
||||
it 'raises error' do
|
||||
result = subject.register_command
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'instance' do
|
||||
subject { described_class.new(current_user: user, **params) }
|
||||
subject { described_class.new(**params) }
|
||||
|
||||
context 'user is admin' do
|
||||
let(:user) { create(:user, :admin) }
|
||||
with_them do
|
||||
let(:params) { { os: commands.each_key.first, arch: 'foo' } }
|
||||
|
||||
with_them do
|
||||
let(:params) { { os: commands.each_key.first, arch: 'foo' } }
|
||||
|
||||
it 'have correct configurations' do
|
||||
result = subject.register_command
|
||||
|
||||
expect(result).to include("#{commands[commands.each_key.first]} register")
|
||||
expect(result).to include("--registration-token $REGISTRATION_TOKEN")
|
||||
expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'user is not admin' do
|
||||
it 'raises error' do
|
||||
it 'have correct configurations' do
|
||||
result = subject.register_command
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
|
||||
expect(result).to include("#{commands[commands.each_key.first]} register")
|
||||
expect(result).to include("--registration-token $REGISTRATION_TOKEN")
|
||||
expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,45 +1,66 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'fast_spec_helper'
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::ErrorTracking::Processor::ContextPayloadProcessor do
|
||||
subject(:processor) { described_class.new }
|
||||
shared_examples 'processing an exception' do
|
||||
before do
|
||||
allow_next_instance_of(Gitlab::ErrorTracking::ContextPayloadGenerator) do |generator|
|
||||
allow(generator).to receive(:generate).and_return(
|
||||
user: { username: 'root' },
|
||||
tags: { locale: 'en', program: 'test', feature_category: 'feature_a', correlation_id: 'cid' },
|
||||
extra: { some_info: 'info' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Gitlab::ErrorTracking::ContextPayloadGenerator) do |generator|
|
||||
allow(generator).to receive(:generate).and_return(
|
||||
user: { username: 'root' },
|
||||
tags: { locale: 'en', program: 'test', feature_category: 'feature_a', correlation_id: 'cid' },
|
||||
extra: { some_info: 'info' }
|
||||
)
|
||||
let(:payload) do
|
||||
{
|
||||
user: { ip_address: '127.0.0.1' },
|
||||
tags: { priority: 'high' },
|
||||
extra: { sidekiq: { class: 'SomeWorker', args: ['[FILTERED]', 1, 2] } }
|
||||
}
|
||||
end
|
||||
|
||||
it 'merges the context payload into event payload', :aggregate_failures do
|
||||
expect(result_hash[:user]).to eq(ip_address: '127.0.0.1', username: 'root')
|
||||
|
||||
expect(result_hash[:tags])
|
||||
.to eq(priority: 'high',
|
||||
locale: 'en',
|
||||
program: 'test',
|
||||
feature_category: 'feature_a',
|
||||
correlation_id: 'cid')
|
||||
|
||||
expect(result_hash[:extra])
|
||||
.to include(some_info: 'info',
|
||||
sidekiq: { class: 'SomeWorker', args: ['[FILTERED]', 1, 2] })
|
||||
end
|
||||
end
|
||||
|
||||
it 'merges the context payload into event payload' do
|
||||
payload = {
|
||||
user: { ip_address: '127.0.0.1' },
|
||||
tags: { priority: 'high' },
|
||||
extra: { sidekiq: { class: 'SomeWorker', args: ['[FILTERED]', 1, 2] } }
|
||||
}
|
||||
describe '.call' do
|
||||
let(:event) { Raven::Event.new(payload) }
|
||||
let(:result_hash) { described_class.call(event).to_hash }
|
||||
|
||||
processor.process(payload)
|
||||
it_behaves_like 'processing an exception'
|
||||
|
||||
expect(payload).to eql(
|
||||
user: {
|
||||
ip_address: '127.0.0.1',
|
||||
username: 'root'
|
||||
},
|
||||
tags: {
|
||||
priority: 'high',
|
||||
locale: 'en',
|
||||
program: 'test',
|
||||
feature_category: 'feature_a',
|
||||
correlation_id: 'cid'
|
||||
},
|
||||
extra: {
|
||||
some_info: 'info',
|
||||
sidekiq: { class: 'SomeWorker', args: ['[FILTERED]', 1, 2] }
|
||||
}
|
||||
)
|
||||
context 'when followed by #process' do
|
||||
let(:result_hash) { described_class.new.process(described_class.call(event).to_hash) }
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#process' do
|
||||
let(:event) { Raven::Event.new(payload) }
|
||||
let(:result_hash) { described_class.new.process(event.to_hash) }
|
||||
|
||||
context 'with sentry_processors_before_send disabled' do
|
||||
before do
|
||||
stub_feature_flags(sentry_processors_before_send: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,73 +3,83 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::ErrorTracking::Processor::GrpcErrorProcessor do
|
||||
describe '#process' do
|
||||
subject { described_class.new }
|
||||
|
||||
shared_examples 'processing an exception' do
|
||||
context 'when there is no GRPC exception' do
|
||||
let(:exception) { RuntimeError.new }
|
||||
let(:data) { { fingerprint: ['ArgumentError', 'Missing arguments'] } }
|
||||
|
||||
it 'leaves data unchanged' do
|
||||
expect(subject.process(data)).to eq(data)
|
||||
expect(result_hash).to include(data)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is a GPRC exception with a debug string' do
|
||||
let(:exception) { GRPC::DeadlineExceeded.new('Deadline Exceeded', {}, '{"hello":1}') }
|
||||
|
||||
let(:data) do
|
||||
{
|
||||
exception: {
|
||||
values: [
|
||||
{
|
||||
type: "GRPC::DeadlineExceeded",
|
||||
value: "4:DeadlineExceeded. debug_error_string:{\"hello\":1}"
|
||||
}
|
||||
]
|
||||
},
|
||||
extra: {
|
||||
caller: 'test'
|
||||
},
|
||||
fingerprint: [
|
||||
"GRPC::DeadlineExceeded",
|
||||
"4:Deadline Exceeded. debug_error_string:{\"created\":\"@1598938192.005782000\",\"description\":\"Error received from peer unix:/home/git/gitalypraefect.socket\",\"file\":\"src/core/lib/surface/call.cc\",\"file_line\":1055,\"grpc_message\":\"Deadline Exceeded\",\"grpc_status\":4}"
|
||||
'GRPC::DeadlineExceeded',
|
||||
'4:Deadline Exceeded. debug_error_string:{"created":"@1598938192.005782000","description":"Error received from peer unix:/home/git/gitalypraefect.socket","file":"src/core/lib/surface/call.cc","file_line":1055,"grpc_message":"Deadline Exceeded","grpc_status":4}'
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
let(:expected) do
|
||||
{
|
||||
fingerprint: [
|
||||
"GRPC::DeadlineExceeded",
|
||||
"4:Deadline Exceeded."
|
||||
],
|
||||
exception: {
|
||||
values: [
|
||||
{
|
||||
type: "GRPC::DeadlineExceeded",
|
||||
value: "4:DeadlineExceeded."
|
||||
}
|
||||
]
|
||||
},
|
||||
extra: {
|
||||
caller: 'test',
|
||||
grpc_debug_error_string: "{\"hello\":1}"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'removes the debug error string and stores it as an extra field' do
|
||||
expect(subject.process(data)).to eq(expected)
|
||||
expect(result_hash[:fingerprint])
|
||||
.to eq(['GRPC::DeadlineExceeded', '4:Deadline Exceeded.'])
|
||||
|
||||
expect(result_hash[:exception][:values].first)
|
||||
.to include(type: 'GRPC::DeadlineExceeded', value: '4:Deadline Exceeded.')
|
||||
|
||||
expect(result_hash[:extra])
|
||||
.to include(caller: 'test', grpc_debug_error_string: '{"hello":1}')
|
||||
end
|
||||
|
||||
context 'with no custom fingerprint' do
|
||||
before do
|
||||
data.delete(:fingerprint)
|
||||
expected.delete(:fingerprint)
|
||||
let(:data) do
|
||||
{ extra: { caller: 'test' } }
|
||||
end
|
||||
|
||||
it 'removes the debug error string and stores it as an extra field' do
|
||||
expect(subject.process(data)).to eq(expected)
|
||||
expect(result_hash).not_to include(:fingerprint)
|
||||
|
||||
expect(result_hash[:exception][:values].first)
|
||||
.to include(type: 'GRPC::DeadlineExceeded', value: '4:Deadline Exceeded.')
|
||||
|
||||
expect(result_hash[:extra])
|
||||
.to include(caller: 'test', grpc_debug_error_string: '{"hello":1}')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.call' do
|
||||
let(:event) { Raven::Event.from_exception(exception, data) }
|
||||
let(:result_hash) { described_class.call(event).to_hash }
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
|
||||
context 'when followed by #process' do
|
||||
let(:result_hash) { described_class.new.process(described_class.call(event).to_hash) }
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#process' do
|
||||
let(:event) { Raven::Event.from_exception(exception, data) }
|
||||
let(:result_hash) { described_class.new.process(event.to_hash) }
|
||||
|
||||
context 'with sentry_processors_before_send disabled' do
|
||||
before do
|
||||
stub_feature_flags(sentry_processors_before_send: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -94,28 +94,37 @@ RSpec.describe Gitlab::ErrorTracking::Processor::SidekiqProcessor do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#process' do
|
||||
shared_examples 'processing an exception' do
|
||||
context 'when there is Sidekiq data' do
|
||||
let(:wrapped_value) { { extra: { sidekiq: value } } }
|
||||
|
||||
shared_examples 'Sidekiq arguments' do |args_in_job_hash: true|
|
||||
let(:path) { [:extra, :sidekiq, args_in_job_hash ? :job : nil, 'args'].compact }
|
||||
let(:args) { [1, 'string', { a: 1 }, [1, 2]] }
|
||||
|
||||
it 'only allows numeric arguments for an unknown worker' do
|
||||
value = { 'args' => args, 'class' => 'UnknownWorker' }
|
||||
context 'for an unknown worker' do
|
||||
let(:value) do
|
||||
hash = { 'args' => args, 'class' => 'UnknownWorker' }
|
||||
|
||||
value = { job: value } if args_in_job_hash
|
||||
args_in_job_hash ? { job: hash } : hash
|
||||
end
|
||||
|
||||
expect(subject.process(extra_sidekiq(value)).dig(*path))
|
||||
.to eq([1, described_class::FILTERED_STRING, described_class::FILTERED_STRING, described_class::FILTERED_STRING])
|
||||
it 'only allows numeric arguments for an unknown worker' do
|
||||
expect(result_hash.dig(*path))
|
||||
.to eq([1, described_class::FILTERED_STRING, described_class::FILTERED_STRING, described_class::FILTERED_STRING])
|
||||
end
|
||||
end
|
||||
|
||||
it 'allows all argument types for a permitted worker' do
|
||||
value = { 'args' => args, 'class' => 'PostReceive' }
|
||||
context 'for a permitted worker' do
|
||||
let(:value) do
|
||||
hash = { 'args' => args, 'class' => 'PostReceive' }
|
||||
|
||||
value = { job: value } if args_in_job_hash
|
||||
args_in_job_hash ? { job: hash } : hash
|
||||
end
|
||||
|
||||
expect(subject.process(extra_sidekiq(value)).dig(*path))
|
||||
.to eq(args)
|
||||
it 'allows all argument types for a permitted worker' do
|
||||
expect(result_hash.dig(*path)).to eq(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -127,39 +136,62 @@ RSpec.describe Gitlab::ErrorTracking::Processor::SidekiqProcessor do
|
|||
include_examples 'Sidekiq arguments', args_in_job_hash: false
|
||||
end
|
||||
|
||||
it 'removes a jobstr field if present' do
|
||||
value = {
|
||||
job: { 'args' => [1] },
|
||||
jobstr: { 'args' => [1] }.to_json
|
||||
}
|
||||
context 'when a jobstr field is present' do
|
||||
let(:value) do
|
||||
{
|
||||
job: { 'args' => [1] },
|
||||
jobstr: { 'args' => [1] }.to_json
|
||||
}
|
||||
end
|
||||
|
||||
expect(subject.process(extra_sidekiq(value)))
|
||||
.to eq(extra_sidekiq(value.except(:jobstr)))
|
||||
it 'removes the jobstr' do
|
||||
expect(result_hash.dig(:extra, :sidekiq)).to eq(value.except(:jobstr))
|
||||
end
|
||||
end
|
||||
|
||||
it 'does nothing with no jobstr' do
|
||||
value = { job: { 'args' => [1] } }
|
||||
context 'when no jobstr value is present' do
|
||||
let(:value) { { job: { 'args' => [1] } } }
|
||||
|
||||
expect(subject.process(extra_sidekiq(value)))
|
||||
.to eq(extra_sidekiq(value))
|
||||
it 'does nothing' do
|
||||
expect(result_hash.dig(:extra, :sidekiq)).to eq(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is no Sidekiq data' do
|
||||
it 'does nothing' do
|
||||
value = {
|
||||
request: {
|
||||
method: 'POST',
|
||||
data: { 'key' => 'value' }
|
||||
}
|
||||
}
|
||||
let(:value) { { tags: { foo: 'bar', baz: 'quux' } } }
|
||||
let(:wrapped_value) { value }
|
||||
|
||||
expect(subject.process(value)).to eq(value)
|
||||
it 'does nothing' do
|
||||
expect(result_hash).to include(value)
|
||||
expect(result_hash.dig(:extra, :sidekiq)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def extra_sidekiq(hash)
|
||||
{ extra: { sidekiq: hash } }
|
||||
describe '.call' do
|
||||
let(:event) { Raven::Event.new(wrapped_value) }
|
||||
let(:result_hash) { described_class.call(event).to_hash }
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
|
||||
context 'when followed by #process' do
|
||||
let(:result_hash) { described_class.new.process(described_class.call(event).to_hash) }
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#process' do
|
||||
let(:event) { Raven::Event.new(wrapped_value) }
|
||||
let(:result_hash) { described_class.new.process(event.to_hash) }
|
||||
|
||||
context 'with sentry_processors_before_send disabled' do
|
||||
before do
|
||||
stub_feature_flags(sentry_processors_before_send: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing an exception'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ require 'raven/transports/dummy'
|
|||
RSpec.describe Gitlab::ErrorTracking do
|
||||
let(:exception) { RuntimeError.new('boom') }
|
||||
let(:issue_url) { 'http://gitlab.com/gitlab-org/gitlab-foss/issues/1' }
|
||||
let(:extra) { { issue_url: issue_url, some_other_info: 'info' } }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
|
|
@ -42,6 +43,8 @@ RSpec.describe Gitlab::ErrorTracking do
|
|||
}
|
||||
end
|
||||
|
||||
let(:sentry_event) { Gitlab::Json.parse(Raven.client.transport.events.last[1]) }
|
||||
|
||||
before do
|
||||
stub_sentry_settings
|
||||
|
||||
|
|
@ -133,8 +136,6 @@ RSpec.describe Gitlab::ErrorTracking do
|
|||
end
|
||||
|
||||
describe '.track_exception' do
|
||||
let(:extra) { { issue_url: issue_url, some_other_info: 'info' } }
|
||||
|
||||
subject(:track_exception) { described_class.track_exception(exception, extra) }
|
||||
|
||||
before do
|
||||
|
|
@ -195,6 +196,55 @@ RSpec.describe Gitlab::ErrorTracking do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the error is kind of an `ActiveRecord::StatementInvalid`' do
|
||||
let(:exception) { ActiveRecord::StatementInvalid.new(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND "users"."foo" = $1') }
|
||||
|
||||
it 'injects the normalized sql query into extra' do
|
||||
track_exception
|
||||
|
||||
expect(sentry_event.dig('extra', 'sql')).to eq('SELECT "users".* FROM "users" WHERE "users"."id" = $2 AND "users"."foo" = $1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the `ActiveRecord::StatementInvalid` is wrapped in another exception' do
|
||||
it 'injects the normalized sql query into extra' do
|
||||
allow(exception).to receive(:cause).and_return(ActiveRecord::StatementInvalid.new(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND "users"."foo" = $1'))
|
||||
|
||||
track_exception
|
||||
|
||||
expect(sentry_event.dig('extra', 'sql')).to eq('SELECT "users".* FROM "users" WHERE "users"."id" = $2 AND "users"."foo" = $1')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'event processors' do
|
||||
subject(:track_exception) { described_class.track_exception(exception, extra) }
|
||||
|
||||
before do
|
||||
allow(Raven).to receive(:capture_exception).and_call_original
|
||||
allow(Gitlab::ErrorTracking::Logger).to receive(:error)
|
||||
end
|
||||
|
||||
context 'custom GitLab context when using Raven.capture_exception directly' do
|
||||
subject(:raven_capture_exception) { Raven.capture_exception(exception) }
|
||||
|
||||
it 'merges a default set of tags into the existing tags' do
|
||||
allow(Raven.context).to receive(:tags).and_return(foo: 'bar')
|
||||
|
||||
raven_capture_exception
|
||||
|
||||
expect(sentry_event['tags']).to include('correlation_id', 'feature_category', 'foo', 'locale', 'program')
|
||||
end
|
||||
|
||||
it 'merges the current user information into the existing user information' do
|
||||
Raven.user_context(id: -1)
|
||||
|
||||
raven_capture_exception
|
||||
|
||||
expect(sentry_event['user']).to eq('id' => -1, 'username' => user.username)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with sidekiq args' do
|
||||
context 'when the args does not have anything sensitive' do
|
||||
let(:extra) { { sidekiq: { 'class' => 'PostReceive', 'args' => [1, { 'id' => 2, 'name' => 'hello' }, 'some-value', 'another-value'] } } }
|
||||
|
|
@ -211,16 +261,20 @@ RSpec.describe Gitlab::ErrorTracking do
|
|||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not filter parameters when sending to Sentry' do
|
||||
track_exception
|
||||
|
||||
expect(sentry_event.dig('extra', 'sidekiq', 'args')).to eq([1, { 'id' => 2, 'name' => 'hello' }, 'some-value', 'another-value'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the args has sensitive information' do
|
||||
let(:extra) { { sidekiq: { 'class' => 'UnknownWorker', 'args' => ['sensitive string', 1, 2] } } }
|
||||
|
||||
it 'filters sensitive arguments before sending' do
|
||||
it 'filters sensitive arguments before sending and logging' do
|
||||
track_exception
|
||||
|
||||
sentry_event = Gitlab::Json.parse(Raven.client.transport.events.last[1])
|
||||
|
||||
expect(sentry_event.dig('extra', 'sidekiq', 'args')).to eq(['[FILTERED]', 1, 2])
|
||||
expect(Gitlab::ErrorTracking::Logger).to have_received(:error).with(
|
||||
hash_including(
|
||||
|
|
@ -234,28 +288,44 @@ RSpec.describe Gitlab::ErrorTracking do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the error is kind of an `ActiveRecord::StatementInvalid`' do
|
||||
let(:exception) { ActiveRecord::StatementInvalid.new(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND "users"."foo" = $1') }
|
||||
context 'when the error is a GRPC error' do
|
||||
context 'when the GRPC error contains a debug_error_string value' do
|
||||
let(:exception) { GRPC::DeadlineExceeded.new('unknown cause', {}, '{"hello":1}') }
|
||||
|
||||
it 'injects the normalized sql query into extra' do
|
||||
allow(Raven.client.transport).to receive(:send_event) do |event|
|
||||
expect(event.extra).to include(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = $2 AND "users"."foo" = $1')
|
||||
it 'sets the GRPC debug error string in the Sentry event and adds a custom fingerprint' do
|
||||
track_exception
|
||||
|
||||
expect(sentry_event.dig('extra', 'grpc_debug_error_string')).to eq('{"hello":1}')
|
||||
expect(sentry_event['fingerprint']).to eq(['GRPC::DeadlineExceeded', '4:unknown cause.'])
|
||||
end
|
||||
|
||||
track_exception
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the `ActiveRecord::StatementInvalid` is wrapped in another exception' do
|
||||
let(:exception) { RuntimeError.new(cause: ActiveRecord::StatementInvalid.new(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND "users"."foo" = $1')) }
|
||||
context 'when the GRPC error does not contain a debug_error_string value' do
|
||||
let(:exception) { GRPC::DeadlineExceeded.new }
|
||||
|
||||
it 'injects the normalized sql query into extra' do
|
||||
allow(Raven.client.transport).to receive(:send_event) do |event|
|
||||
expect(event.extra).to include(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = $2 AND "users"."foo" = $1')
|
||||
it 'does not do any processing on the event' do
|
||||
track_exception
|
||||
|
||||
expect(sentry_event['extra']).not_to include('grpc_debug_error_string')
|
||||
expect(sentry_event['fingerprint']).to eq(['GRPC::DeadlineExceeded', '4:unknown cause'])
|
||||
end
|
||||
|
||||
track_exception
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with sentry_processors_before_send enabled' do
|
||||
before do
|
||||
stub_feature_flags(sentry_processors_before_send: true)
|
||||
end
|
||||
|
||||
include_examples 'event processors'
|
||||
end
|
||||
|
||||
context 'with sentry_processors_before_send disabled' do
|
||||
before do
|
||||
stub_feature_flags(sentry_processors_before_send: false)
|
||||
end
|
||||
|
||||
include_examples 'event processors'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
|
|||
let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) }
|
||||
|
||||
before do
|
||||
pipeline.persistent_ref.create
|
||||
pipeline.persistent_ref.create # rubocop:disable Rails/SaveBang
|
||||
end
|
||||
|
||||
it 'returns the correct refspecs' do
|
||||
|
|
@ -261,7 +261,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
|
|||
let(:build) { create(:ci_build, pipeline: pipeline) }
|
||||
|
||||
before do
|
||||
pipeline.persistent_ref.create
|
||||
pipeline.persistent_ref.create # rubocop:disable Rails/SaveBang
|
||||
end
|
||||
|
||||
it 'exposes the persistent pipeline ref' do
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ RSpec.describe Ci::TriggerPresenter do
|
|||
|
||||
context 'when user is a trigger owner and builds admin' do
|
||||
before do
|
||||
trigger.update(owner: user)
|
||||
trigger.update!(owner: user)
|
||||
end
|
||||
|
||||
describe '#token' do
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ RSpec.describe ::Packages::Conan::PackagePresenter do
|
|||
before do
|
||||
[info_file, manifest_file, package_file].each do |file|
|
||||
file.conan_file_metadatum.conan_package_reference = alternative_reference
|
||||
file.save
|
||||
file.save!
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -38,16 +38,16 @@ RSpec.describe API::Internal::Kubernetes do
|
|||
end
|
||||
|
||||
shared_examples 'agent authentication' do
|
||||
it 'returns 403 if Authorization header not sent' do
|
||||
it 'returns 401 if Authorization header not sent' do
|
||||
send_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 403 if Authorization is for non-existent agent' do
|
||||
it 'returns 401 if Authorization is for non-existent agent' do
|
||||
send_request(headers: { 'Authorization' => 'Bearer NONEXISTENT' })
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ func TestConfigDefaults(t *testing.T) {
|
|||
DocumentRoot: "public",
|
||||
ProxyHeadersTimeout: 5 * time.Minute,
|
||||
APIQueueTimeout: queueing.DefaultTimeout,
|
||||
APICILongPollingDuration: 50 * time.Second,
|
||||
APICILongPollingDuration: 50 * time.Nanosecond, // TODO this is meant to be 50*time.Second but it has been wrong for ages
|
||||
ImageResizerConfig: config.DefaultImageResizerConfig,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ func buildConfig(arg0 string, args []string) (*bootConfig, *config.Config, error
|
|||
fset.UintVar(&cfg.APILimit, "apiLimit", 0, "Number of API requests allowed at single time")
|
||||
fset.UintVar(&cfg.APIQueueLimit, "apiQueueLimit", 0, "Number of API requests allowed to be queued")
|
||||
fset.DurationVar(&cfg.APIQueueTimeout, "apiQueueDuration", queueing.DefaultTimeout, "Maximum queueing duration of requests")
|
||||
fset.DurationVar(&cfg.APICILongPollingDuration, "apiCiLongPollingDuration", 50*time.Second, "Long polling duration for job requesting for runners (default 50s - enabled)")
|
||||
fset.DurationVar(&cfg.APICILongPollingDuration, "apiCiLongPollingDuration", 50, "Long polling duration for job requesting for runners (default 50s - enabled)")
|
||||
fset.BoolVar(&cfg.PropagateCorrelationID, "propagateCorrelationID", false, "Reuse existing Correlation-ID from the incoming request header `X-Request-ID` if present")
|
||||
|
||||
if err := fset.Parse(args); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue