Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/behaviors/preview_markdown.js7
-rw-r--r--app/assets/javascripts/dropzone_input.js1
-rw-r--r--app/assets/javascripts/issues/list/utils.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue75
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/constants.js2
-rw-r--r--app/controllers/graphql_controller.rb7
-rw-r--r--app/finders/fork_targets_finder.rb4
-rw-r--r--app/helpers/search_helper.rb2
-rw-r--r--app/helpers/sorting_titles_values_helper.rb4
-rw-r--r--app/models/user.rb4
-rw-r--r--app/policies/global_policy.rb2
-rw-r--r--app/views/groups/runners/_runner.html.haml2
-rw-r--r--app/views/projects/buttons/_fork.html.haml2
-rw-r--r--app/views/projects/forks/index.html.haml2
-rw-r--r--config/application.rb3
-rw-r--r--db/post_migrate/20220110171049_schedule_populate_test_reports_issue_id.rb23
-rw-r--r--db/schema_migrations/202201101710491
-rw-r--r--doc/ci/environments/deployment_approvals.md2
-rw-r--r--doc/development/testing_guide/end_to_end/feature_flags.md26
-rw-r--r--doc/user/packages/package_registry/index.md19
-rw-r--r--lib/gitlab/background_migration/populate_test_reports_issue_id.rb14
-rw-r--r--lib/gitlab/exceptions_app.rb43
-rw-r--r--locale/gitlab.pot6
-rw-r--r--public/500.html1
-rw-r--r--qa/qa/fixtures/metrics_dashboards/templating.yml2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/gitlab_migration_group_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/.gitkeep0
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb142
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/cluster_with_prometheus.rb67
-rw-r--r--spec/features/dashboard/user_filters_projects_spec.rb6
-rw-r--r--spec/features/groups/labels/sort_labels_spec.rb2
-rw-r--r--spec/features/issuables/sorting_list_spec.rb16
-rw-r--r--spec/features/projects/branches_spec.rb4
-rw-r--r--spec/features/projects/labels/sort_labels_spec.rb2
-rw-r--r--spec/features/projects/user_sorts_projects_spec.rb4
-rw-r--r--spec/features/user_sorts_things_spec.rb6
-rw-r--r--spec/finders/fork_targets_finder_spec.rb8
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap2
-rw-r--r--spec/frontend/vue_shared/components/markdown/field_spec.js36
-rw-r--r--spec/helpers/search_helper_spec.rb2
-rw-r--r--spec/lib/error_tracking/collector/payload_validator_spec.rb38
-rw-r--r--spec/lib/gitlab/exceptions_app_spec.rb68
-rw-r--r--spec/models/integrations/asana_spec.rb132
-rw-r--r--spec/models/user_spec.rb11
-rw-r--r--spec/services/error_tracking/collect_error_service_spec.rb24
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb186
46 files changed, 540 insertions, 479 deletions
diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js
index a548b283142..679940d1317 100644
--- a/app/assets/javascripts/behaviors/preview_markdown.js
+++ b/app/assets/javascripts/behaviors/preview_markdown.js
@@ -124,13 +124,6 @@ const writeButtonSelector = '.js-md-write-button';
lastTextareaPreviewed = null;
const markdownToolbar = $('.md-header-toolbar');
-$.fn.setupMarkdownPreview = function () {
- const $form = $(this);
- $form.find('textarea.markdown-area').on('input', () => {
- markdownPreview.hideReferencedUsers($form);
- });
-};
-
$(document).on('markdown-preview:show', (e, $form) => {
if (!$form) {
return;
diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js
index 7c7127dfa44..491c2ced358 100644
--- a/app/assets/javascripts/dropzone_input.js
+++ b/app/assets/javascripts/dropzone_input.js
@@ -51,7 +51,6 @@ export default function dropzoneInput(form, config = { parallelUploads: 2 }) {
// Add dropzone area to the form.
const $mdArea = formTextarea.closest('.md-area');
- form.setupMarkdownPreview();
const $formDropzone = form.find('.div-dropzone');
$formDropzone.parent().addClass('div-dropzone-wrapper');
$formDropzone.append(divHover);
diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js
index c64925edc28..2919bbbfef8 100644
--- a/app/assets/javascripts/issues/list/utils.js
+++ b/app/assets/javascripts/issues/list/utils.js
@@ -72,7 +72,7 @@ export const getSortOptions = (hasIssueWeightsFeature, hasBlockedIssuesFeature)
},
{
id: 3,
- title: __('Last updated'),
+ title: __('Updated date'),
sortDirection: {
ascending: UPDATED_ASC,
descending: UPDATED_DESC,
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 86f04c78ebe..5c86c928ce3 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -2,7 +2,7 @@
import { GlIcon } from '@gitlab/ui';
import $ from 'jquery';
import '~/behaviors/markdown/render_gfm';
-import { unescape } from 'lodash';
+import { debounce, unescape } from 'lodash';
import createFlash from '~/flash';
import GLForm from '~/gl_form';
import axios from '~/lib/utils/axios_utils';
@@ -110,7 +110,7 @@ export default {
return {
markdownPreview: '',
referencedCommands: '',
- referencedUsers: '',
+ referencedUsers: [],
hasSuggestion: false,
markdownPreviewLoading: false,
previewMarkdown: false,
@@ -188,6 +188,24 @@ export default {
});
}
},
+
+ textareaValue: {
+ immediate: true,
+ handler(textareaValue, oldVal) {
+ const all = /@all([^\w._-]|$)/;
+ const hasAll = all.test(textareaValue);
+ const hadAll = all.test(oldVal);
+
+ const justAddedAll = !hadAll && hasAll;
+ const justRemovedAll = hadAll && !hasAll;
+
+ if (justAddedAll) {
+ this.debouncedFetchMarkdown();
+ } else if (justRemovedAll) {
+ this.referencedUsers = [];
+ }
+ },
+ },
},
mounted() {
// GLForm class handles all the toolbar buttons
@@ -222,9 +240,9 @@ export default {
if (this.textareaValue) {
this.markdownPreviewLoading = true;
this.markdownPreview = __('Loading…');
- axios
- .post(this.markdownPreviewPath, { text: this.textareaValue })
- .then((response) => this.renderMarkdown(response.data))
+
+ this.fetchMarkdown()
+ .then((data) => this.renderMarkdown(data))
.catch(() =>
createFlash({
message: __('Error loading markdown preview'),
@@ -239,17 +257,28 @@ export default {
this.previewMarkdown = false;
},
+ fetchMarkdown() {
+ return axios.post(this.markdownPreviewPath, { text: this.textareaValue }).then(({ data }) => {
+ const { references } = data;
+ if (references) {
+ this.referencedCommands = references.commands;
+ this.referencedUsers = references.users;
+ this.hasSuggestion = references.suggestions?.length > 0;
+ this.suggestions = references.suggestions;
+ }
+
+ return data;
+ });
+ },
+
+ debouncedFetchMarkdown: debounce(function debouncedFetchMarkdown() {
+ return this.fetchMarkdown();
+ }, 400),
+
renderMarkdown(data = {}) {
this.markdownPreviewLoading = false;
this.markdownPreview = data.body || __('Nothing to preview.');
- if (data.references) {
- this.referencedCommands = data.references.commands;
- this.referencedUsers = data.references.users;
- this.hasSuggestion = data.references.suggestions && data.references.suggestions.length;
- this.suggestions = data.references.suggestions;
- }
-
this.$nextTick()
.then(() => $(this.$refs['markdown-preview']).renderGFM())
.catch(() =>
@@ -326,18 +355,14 @@ export default {
v-html="markdownPreview /* eslint-disable-line vue/no-v-html */"
></div>
</template>
- <template v-if="previewMarkdown && !markdownPreviewLoading">
- <div
- v-if="referencedCommands"
- class="referenced-commands"
- v-html="referencedCommands /* eslint-disable-line vue/no-v-html */"
- ></div>
- <div v-if="shouldShowReferencedUsers" class="referenced-users">
- <gl-icon name="warning-solid" />
- <span
- v-html="addMultipleToDiscussionWarning /* eslint-disable-line vue/no-v-html */"
- ></span>
- </div>
- </template>
+ <div
+ v-if="referencedCommands && previewMarkdown && !markdownPreviewLoading"
+ class="referenced-commands"
+ v-html="referencedCommands /* eslint-disable-line vue/no-v-html */"
+ ></div>
+ <div v-if="shouldShowReferencedUsers" class="referenced-users">
+ <gl-icon name="warning-solid" />
+ <span v-html="addMultipleToDiscussionWarning /* eslint-disable-line vue/no-v-html */"></span>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/issuable/list/constants.js b/app/assets/javascripts/vue_shared/issuable/list/constants.js
index 773ad0f8e93..c6dce6a51c2 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/constants.js
+++ b/app/assets/javascripts/vue_shared/issuable/list/constants.js
@@ -38,7 +38,7 @@ export const AvailableSortOptions = [
},
{
id: 2,
- title: __('Last updated'),
+ title: __('Updated date'),
sortDirection: {
descending: 'updated_desc',
ascending: 'updated_asc',
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index f48d03869a4..689ca32f6d9 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -44,6 +44,13 @@ class GraphqlController < ApplicationController
# The default feature category is overridden to read from request
feature_category :not_owned
+ # We don't know what the query is going to be, so we can't set a high urgency
+ # See https://gitlab.com/groups/gitlab-org/-/epics/5841 for the work that will
+ # allow us to specify an urgency per query.
+ # Currently, all queries have a default urgency. And this is measured in the `graphql_queries`
+ # SLI. But queries could be multiplexed, so the total duration could be longer.
+ urgency :low, [:execute]
+
def execute
result = multiplex? ? execute_multiplex : execute_query
render json: result
diff --git a/app/finders/fork_targets_finder.rb b/app/finders/fork_targets_finder.rb
index 3a79b216853..0b5dfb16572 100644
--- a/app/finders/fork_targets_finder.rb
+++ b/app/finders/fork_targets_finder.rb
@@ -8,9 +8,9 @@ class ForkTargetsFinder
# rubocop: disable CodeReuse/ActiveRecord
def execute(options = {})
- return ::Namespace.where(id: user.manageable_namespaces).sort_by_type unless options[:only_groups]
+ return ::Namespace.where(id: user.forkable_namespaces).sort_by_type unless options[:only_groups]
- ::Group.where(id: user.manageable_groups)
+ ::Group.where(id: user.manageable_groups(include_groups_with_developer_maintainer_access: true))
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 7970151d603..6efede8d565 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -141,7 +141,7 @@ module SearchHelper
}
},
{
- title: _('Last updated'),
+ title: _('Updated date'),
sortable: true,
sortParam: {
asc: 'updated_asc',
diff --git a/app/helpers/sorting_titles_values_helper.rb b/app/helpers/sorting_titles_values_helper.rb
index 75ba6e8a153..4dfa7689110 100644
--- a/app/helpers/sorting_titles_values_helper.rb
+++ b/app/helpers/sorting_titles_values_helper.rb
@@ -59,7 +59,7 @@ module SortingTitlesValuesHelper
end
def sort_title_latest_activity
- s_('SortOptions|Last updated')
+ _('Updated date')
end
def sort_title_milestone
@@ -127,7 +127,7 @@ module SortingTitlesValuesHelper
end
def sort_title_recently_updated
- s_('SortOptions|Last updated')
+ _('Updated date')
end
def sort_title_start_date_later
diff --git a/app/models/user.rb b/app/models/user.rb
index 8e954aac1ba..406eb2d6204 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1535,8 +1535,8 @@ class User < ApplicationRecord
end
end
- def manageable_namespaces
- @manageable_namespaces ||= [namespace] + manageable_groups
+ def forkable_namespaces
+ @forkable_namespaces ||= [namespace] + manageable_groups(include_groups_with_developer_maintainer_access: true)
end
def manageable_groups(include_groups_with_developer_maintainer_access: false)
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index c3b4b163cb4..2a2ddf29899 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -9,7 +9,7 @@ class GlobalPolicy < BasePolicy
with_options scope: :user, score: 0
condition(:access_locked) { @user&.access_locked? }
- condition(:can_create_fork, scope: :user) { @user && @user.manageable_namespaces.any? { |namespace| @user.can?(:create_projects, namespace) } }
+ condition(:can_create_fork, scope: :user) { @user && @user.forkable_namespaces.any? { |namespace| @user.can?(:create_projects, namespace) } }
condition(:required_terms_not_accepted, scope: :user, score: 0) do
@user&.required_terms_not_accepted?
diff --git a/app/views/groups/runners/_runner.html.haml b/app/views/groups/runners/_runner.html.haml
index 3bb1ad421ca..78ce5b3e110 100644
--- a/app/views/groups/runners/_runner.html.haml
+++ b/app/views/groups/runners/_runner.html.haml
@@ -76,5 +76,5 @@
= sprite_icon('close', css_class: 'gl-icon')
- else
.btn-group
- = link_to group_runner_path(@group, runner), method: :delete, class: 'gl-button btn btn-danger btn-icon has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do
+ = link_to group_runner_path(@group, runner), method: :delete, class: 'gl-button btn btn-danger btn-icon has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?'), confirm_btn_variant: "danger" } do
= sprite_icon('close', css_class: 'gl-icon')
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index 3cec7fd9eb8..c57b6dbe28c 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -1,7 +1,7 @@
- unless @project.empty_repo?
- if current_user
.count-badge.btn-group
- - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
+ - if current_user.already_forked?(@project) && current_user.forkable_namespaces.size < 2
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: s_('ProjectOverview|Go to your fork'), class: 'gl-button btn btn-default btn-sm has-tooltip fork-btn' do
= sprite_icon('fork', css_class: 'icon')
%span= s_('ProjectOverview|Fork')
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index d6f421e8ad6..5330c3aa6d6 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -25,7 +25,7 @@
= forks_sort_direction_button(sort_value)
- if current_user && can?(current_user, :fork_project, @project)
- - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
+ - if current_user.already_forked?(@project) && current_user.forkable_namespaces.size < 2
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn gl-button btn-confirm gl-md-ml-3' do
= sprite_icon('fork', size: 12)
%span= _('Fork')
diff --git a/config/application.rb b/config/application.rb
index f64e5c998eb..68b68c1c886 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -68,6 +68,9 @@ module Gitlab
require_dependency Rails.root.join('lib/gitlab/middleware/rack_multipart_tempfile_factory')
require_dependency Rails.root.join('lib/gitlab/runtime')
require_dependency Rails.root.join('lib/gitlab/patch/legacy_database_config')
+ require_dependency Rails.root.join('lib/gitlab/exceptions_app')
+
+ config.exceptions_app = Gitlab::ExceptionsApp.new(Rails.public_path)
# To be removed in 15.0
# This preload is needed to convert legacy `database.yml`
diff --git a/db/post_migrate/20220110171049_schedule_populate_test_reports_issue_id.rb b/db/post_migrate/20220110171049_schedule_populate_test_reports_issue_id.rb
new file mode 100644
index 00000000000..dae93e1636d
--- /dev/null
+++ b/db/post_migrate/20220110171049_schedule_populate_test_reports_issue_id.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class SchedulePopulateTestReportsIssueId < Gitlab::Database::Migration[1.0]
+ MIGRATION = 'PopulateTestReportsIssueId'
+ DELAY_INTERVAL = 2.minutes.to_i
+ BATCH_SIZE = 30
+
+ disable_ddl_transaction!
+
+ def up
+ queue_background_migration_jobs_by_range_at_intervals(
+ define_batchable_model('requirements_management_test_reports').where(issue_id: nil),
+ MIGRATION,
+ DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ track_jobs: true
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20220110171049 b/db/schema_migrations/20220110171049
new file mode 100644
index 00000000000..ab39a1afb25
--- /dev/null
+++ b/db/schema_migrations/20220110171049
@@ -0,0 +1 @@
+55ad00b1cf70f5d1a3f033efccf64c2c273ad03f65823a2281869849571ab35b \ No newline at end of file
diff --git a/doc/ci/environments/deployment_approvals.md b/doc/ci/environments/deployment_approvals.md
index feb76947609..d60e5704877 100644
--- a/doc/ci/environments/deployment_approvals.md
+++ b/doc/ci/environments/deployment_approvals.md
@@ -7,7 +7,7 @@ description: Require approvals prior to deploying to a Protected Environment
# Deployment approvals **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215888) in GitLab 14.7 with a flag named `deployment_approvals`. Disabled by default.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/343864) in GitLab 14.7 with a flag named `deployment_approvals`. Disabled by default.
WARNING:
This feature is in an alpha stage and subject to change without prior notice.
diff --git a/doc/development/testing_guide/end_to_end/feature_flags.md b/doc/development/testing_guide/end_to_end/feature_flags.md
index de34e6a1872..48157a961e1 100644
--- a/doc/development/testing_guide/end_to_end/feature_flags.md
+++ b/doc/development/testing_guide/end_to_end/feature_flags.md
@@ -118,6 +118,32 @@ view 'app/views/devise/passwords/new_edit_behind_ff.html.haml' do
end
```
+## Working with resource classes
+
+If a resource class must behave differently when a feature flag is active, toggle a
+variable with the name of the feature flag inside the class. This variable and condition
+ensure all actions are handled appropriately.
+
+You can set this variable inside the `fabricate_via_api` call. For a consistent approach:
+
+- Use an `activated` check, not a deactivated one.
+- Add the word `activated` to the end of a variable's name.
+- Inside the `initialize` method, set the variable's default value.
+
+For example:
+
+```ruby
+def initialize
+ name_of_the_future_flag_activated = false
+ ...
+end
+```
+
+### Cleanup
+
+After the feature flag is removed, clean up the resource class and delete the variable.
+All methods should use the condition procedures of the now-default state.
+
## Running a scenario with a feature flag enabled
It's also possible to run an entire scenario with a feature flag enabled, without having to edit
diff --git a/doc/user/packages/package_registry/index.md b/doc/user/packages/package_registry/index.md
index 28e1571b4f8..3311b271126 100644
--- a/doc/user/packages/package_registry/index.md
+++ b/doc/user/packages/package_registry/index.md
@@ -32,6 +32,25 @@ When you view packages in a group:
For information on how to create and upload a package, view the GitLab documentation for your package type.
+## Authenticate with the registry
+
+Authentication depends on the package manager being used. For more information, see the docs on the
+specific package format you want to use.
+
+For most package types, the following credential types are valid:
+
+- [Personal access token](../../profile/personal_access_tokens.md):
+ authenticates with your user permissions. Good for personal and local use of the package registry.
+- [Project deploy token](../../project/deploy_tokens/index.md):
+ allows access to all packages in a project. Good for granting and revoking project access to many
+ users.
+- [Group deploy token](../../project/deploy_tokens/index.md#group-deploy-token):
+ allows access to all packages in a group and its subgroups. Good for granting and revoking access
+ to a large number of packages to sets of users.
+- [Job token](../../../ci/jobs/ci_job_token.md):
+ allows access to packages in the project running the job for the users running the pipeline.
+ Access to other external projects can be configured.
+
## Use GitLab CI/CD to build packages
You can use [GitLab CI/CD](../../../ci/index.md) to build packages.
diff --git a/lib/gitlab/background_migration/populate_test_reports_issue_id.rb b/lib/gitlab/background_migration/populate_test_reports_issue_id.rb
new file mode 100644
index 00000000000..301efd0c943
--- /dev/null
+++ b/lib/gitlab/background_migration/populate_test_reports_issue_id.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+# rubocop: disable Style/Documentation
+
+module Gitlab
+ module BackgroundMigration
+ class PopulateTestReportsIssueId
+ def perform(start_id, stop_id)
+ # NO OP
+ end
+ end
+ end
+end
+
+Gitlab::BackgroundMigration::PopulateTestReportsIssueId.prepend_mod
diff --git a/lib/gitlab/exceptions_app.rb b/lib/gitlab/exceptions_app.rb
new file mode 100644
index 00000000000..de07b788fb9
--- /dev/null
+++ b/lib/gitlab/exceptions_app.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require_relative 'utils/override'
+
+module Gitlab
+ class ExceptionsApp < ActionDispatch::PublicExceptions
+ extend ::Gitlab::Utils::Override
+
+ REQUEST_ID_PLACEHOLDER = '<!-- REQUEST_ID -->'
+ REQUEST_ID_PARAGRAPH = '<p>Request ID: <code>%s</code></p>'
+
+ override :call
+ def call(env)
+ status, headers, body = super
+
+ if html_rendered? && body.first&.include?(REQUEST_ID_PLACEHOLDER)
+ body = [insert_request_id(env, body.first)]
+ headers['X-GitLab-Custom-Error'] = '1'
+ end
+
+ [status, headers, body]
+ end
+
+ private
+
+ override :render_html
+ def render_html(status)
+ @html_rendered = true
+
+ super
+ end
+
+ def html_rendered?
+ !!@html_rendered
+ end
+
+ def insert_request_id(env, body)
+ request_id = ERB::Util.html_escape(ActionDispatch::Request.new(env).request_id)
+
+ body.gsub(REQUEST_ID_PLACEHOLDER, REQUEST_ID_PARAGRAPH % [request_id])
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 4b28f3b6b2f..e3596b766d3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -33574,9 +33574,6 @@ msgstr ""
msgid "SortOptions|Last created"
msgstr ""
-msgid "SortOptions|Last updated"
-msgstr ""
-
msgid "SortOptions|Least popular"
msgstr ""
@@ -38264,6 +38261,9 @@ msgstr ""
msgid "Updated %{updated_at} by %{updated_by}"
msgstr ""
+msgid "Updated date"
+msgstr ""
+
msgid "Updates"
msgstr ""
diff --git a/public/500.html b/public/500.html
index df7b22dc9ef..16d72353bdb 100644
--- a/public/500.html
+++ b/public/500.html
@@ -76,6 +76,7 @@
<div class="container">
<h3>Whoops, something went wrong on our end.</h3>
<hr />
+ <!-- REQUEST_ID -->
<p>Try refreshing the page, or going back and attempting the action again.</p>
<p>Please contact your GitLab administrator if this problem persists.</p>
<a href="javascript:history.back()" class="js-go-back go-back">Go back</a>
diff --git a/qa/qa/fixtures/metrics_dashboards/templating.yml b/qa/qa/fixtures/metrics_dashboards/templating.yml
index e06e7cc1247..847eba59bd2 100644
--- a/qa/qa/fixtures/metrics_dashboards/templating.yml
+++ b/qa/qa/fixtures/metrics_dashboards/templating.yml
@@ -40,4 +40,4 @@ panel_groups:
- id: pod_memory_working_set1
query_range: 'container_memory_working_set_bytes{pod_name=~"{{pod_name2}}"}/1024/1024'
unit: "MiB"
- label: pod_name
+ label: pod_name \ No newline at end of file
diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/gitlab_migration_group_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/gitlab_migration_group_spec.rb
index 904f88e8c14..a18e22f52f1 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/group/gitlab_migration_group_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/gitlab_migration_group_spec.rb
@@ -2,12 +2,7 @@
module QA
describe 'Manage', :requires_admin do
- describe 'Gitlab migration', quarantine: {
- only: { subdomain: :staging },
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/349556",
- type: :bug
- } do
- let!(:staging?) { Runtime::Scenario.gitlab_address.include?('staging.gitlab.com') }
+ describe 'Gitlab migration' do
let!(:admin_api_client) { Runtime::API::Client.as_admin }
let!(:user) do
Resource::User.fabricate_via_api! do |usr|
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/.gitkeep b/qa/qa/specs/features/browser_ui/8_monitor/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/8_monitor/.gitkeep
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
deleted file mode 100644
index c13d2d2dddf..00000000000
--- a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
+++ /dev/null
@@ -1,142 +0,0 @@
-# frozen_string_literal: true
-require_relative 'cluster_with_prometheus'
-
-module QA
- RSpec.describe 'Monitor', :orchestrated, :kubernetes, :requires_admin, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/241448', type: :investigating } do
- include_context "cluster with Prometheus installed"
-
- before do
- Flow::Login.sign_in_unless_signed_in
- @project.visit!
- end
-
- it 'configures custom metrics', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348082' do
- verify_add_custom_metric
- verify_edit_custom_metric
- verify_delete_custom_metric
- end
-
- it 'duplicates to create dashboard to custom', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348070' do
- Page::Project::Menu.perform(&:go_to_monitor_metrics)
-
- Page::Project::Monitor::Metrics::Show.perform do |on_dashboard|
- on_dashboard.duplicate_dashboard
-
- expect(on_dashboard).to have_metrics
- expect(on_dashboard).to have_edit_dashboard_enabled
- end
- end
-
- it 'verifies data on filtered deployed environment', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348071' do
- Page::Project::Menu.perform(&:go_to_monitor_metrics)
-
- Page::Project::Monitor::Metrics::Show.perform do |on_dashboard|
- on_dashboard.filter_environment
-
- expect(on_dashboard).to have_metrics
- end
- end
-
- it 'filters using the quick range', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348083' do
- Page::Project::Menu.perform(&:go_to_monitor_metrics)
-
- Page::Project::Monitor::Metrics::Show.perform do |on_dashboard|
- on_dashboard.show_last('30 minutes')
- expect(on_dashboard).to have_metrics
-
- on_dashboard.show_last('3 hours')
- expect(on_dashboard).to have_metrics
-
- on_dashboard.show_last('1 day')
- expect(on_dashboard).to have_metrics
- end
- end
-
- it 'observes cluster health graph', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348074' do
- Page::Project::Menu.perform(&:go_to_infrastructure_kubernetes)
-
- Page::Project::Infrastructure::Kubernetes::Index.perform do |cluster_list|
- cluster_list.click_on_cluster(@cluster)
- end
-
- Page::Project::Infrastructure::Kubernetes::Show.perform do |cluster_panel|
- cluster_panel.open_health
- cluster_panel.wait_for_cluster_health
- end
- end
-
- it 'uses templating variables for metrics dashboards', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347636' do
- templating_dashboard_yml = Pathname
- .new(__dir__)
- .join('../../../../fixtures/metrics_dashboards/templating.yml')
-
- Resource::Repository::ProjectPush.fabricate! do |push|
- push.project = @project
- push.file_name = '.gitlab/dashboards/templating.yml'
- push.file_content = File.read(templating_dashboard_yml)
- push.commit_message = 'Add templating in dashboard file'
- push.new_branch = false
- end
-
- Page::Project::Menu.perform(&:go_to_monitor_metrics)
-
- Page::Project::Monitor::Metrics::Show.perform do |dashboard|
- dashboard.select_dashboard('templating.yml')
-
- expect(dashboard).to have_template_metric('CPU usage GitLab Runner')
- expect(dashboard).to have_template_metric('Memory usage Postgresql')
- expect(dashboard).to have_templating_variable('GitLab Runner')
- expect(dashboard).to have_templating_variable('Postgresql')
- end
- end
-
- private
-
- def verify_add_custom_metric
- Page::Project::Menu.perform(&:go_to_integrations_settings)
- Page::Project::Settings::Integrations.perform(&:click_on_prometheus_integration)
-
- Page::Project::Settings::Services::Prometheus.perform do |metrics_panel|
- metrics_panel.click_on_new_metric
- metrics_panel.add_custom_metric
- end
-
- Page::Project::Menu.perform(&:go_to_monitor_metrics)
-
- Page::Project::Monitor::Metrics::Show.perform do |on_dashboard|
- expect(on_dashboard).to have_custom_metric('HTTP Requests Total')
- end
- end
-
- def verify_edit_custom_metric
- Page::Project::Menu.perform(&:go_to_integrations_settings)
- Page::Project::Settings::Integrations.perform(&:click_on_prometheus_integration)
- Page::Project::Settings::Services::Prometheus.perform do |metrics_panel|
- metrics_panel.click_on_custom_metric('Business / HTTP Requests Total (req/sec)')
- metrics_panel.edit_custom_metric
- end
-
- Page::Project::Menu.perform(&:go_to_monitor_metrics)
-
- Page::Project::Monitor::Metrics::Show.perform do |on_dashboard|
- expect(on_dashboard).to have_custom_metric('Throughput')
- end
- end
-
- def verify_delete_custom_metric
- Page::Project::Menu.perform(&:go_to_integrations_settings)
- Page::Project::Settings::Integrations.perform(&:click_on_prometheus_integration)
-
- Page::Project::Settings::Services::Prometheus.perform do |metrics_panel|
- metrics_panel.click_on_custom_metric('Business / Throughput (req/sec)')
- metrics_panel.delete_custom_metric
- end
-
- Page::Project::Menu.perform(&:go_to_monitor_metrics)
-
- Page::Project::Monitor::Metrics::Show.perform do |on_dashboard|
- expect(on_dashboard).not_to have_custom_metric('Throughput')
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/cluster_with_prometheus.rb b/qa/qa/specs/features/browser_ui/8_monitor/cluster_with_prometheus.rb
deleted file mode 100644
index 19e49400d5e..00000000000
--- a/qa/qa/specs/features/browser_ui/8_monitor/cluster_with_prometheus.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.shared_context "cluster with Prometheus installed" do
- before :all do
- @cluster = Service::KubernetesCluster.new(provider_class: Service::ClusterProvider::K3s).create!
- @project = Resource::Project.fabricate_via_api! do |project|
- project.name = 'monitoring-project'
- project.auto_devops_enabled = true
- project.template_name = 'express'
- end
-
- deploy_project_with_prometheus
- end
-
- def deploy_project_with_prometheus
- %w[
- CODE_QUALITY_DISABLED TEST_DISABLED LICENSE_MANAGEMENT_DISABLED
- SAST_DISABLED DAST_DISABLED DEPENDENCY_SCANNING_DISABLED
- CONTAINER_SCANNING_DISABLED BROWSER_PERFORMANCE_DISABLED SECRET_DETECTION_DISABLED
- ].each do |key|
- Resource::CiVariable.fabricate_via_api! do |resource|
- resource.project = @project
- resource.key = key
- resource.value = '1'
- resource.masked = false
- end
- end
-
- Flow::Login.sign_in
-
- Resource::KubernetesCluster::ProjectCluster.fabricate! do |cluster_settings|
- cluster_settings.project = @project
- cluster_settings.cluster = @cluster
- cluster_settings.install_runner = true
- cluster_settings.install_ingress = true
- cluster_settings.install_prometheus = true
- end
-
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = @project
- end.visit!
-
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('build')
- end
- Page::Project::Job::Show.perform do |job|
- expect(job).to be_successful(timeout: 600)
-
- job.click_element(:pipeline_path)
- end
-
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('production')
- end
- Page::Project::Job::Show.perform do |job|
- expect(job).to be_successful(timeout: 1200)
-
- job.click_element(:pipeline_path)
- end
- end
-
- after :all do
- @cluster&.remove!
- end
- end
-end
diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb
index 9fa77d5917d..f6821ae66e8 100644
--- a/spec/features/dashboard/user_filters_projects_spec.rb
+++ b/spec/features/dashboard/user_filters_projects_spec.rb
@@ -168,7 +168,7 @@ RSpec.describe 'Dashboard > User filters projects' do
sorting_dropdown.click
- ['Last updated', 'Created date', 'Name', 'Stars'].each do |label|
+ ['Updated date', 'Created date', 'Name', 'Stars'].each do |label|
expect(sorting_dropdown).to have_content(label)
end
end
@@ -192,9 +192,9 @@ RSpec.describe 'Dashboard > User filters projects' do
end
end
- context 'Sorting by Last updated' do
+ context 'Sorting by Updated date' do
it 'sorts the project list' do
- select_dropdown_option '#filtered-search-sorting-dropdown', 'Last updated'
+ select_dropdown_option '#filtered-search-sorting-dropdown', 'Updated date'
expect_to_see_projects(desc_sorted_project_names)
diff --git a/spec/features/groups/labels/sort_labels_spec.rb b/spec/features/groups/labels/sort_labels_spec.rb
index b5657db23cb..df75ff7c3cb 100644
--- a/spec/features/groups/labels/sort_labels_spec.rb
+++ b/spec/features/groups/labels/sort_labels_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe 'Sort labels', :js do
expect(sort_options[1]).to eq('Name, descending')
expect(sort_options[2]).to eq('Last created')
expect(sort_options[3]).to eq('Oldest created')
- expect(sort_options[4]).to eq('Last updated')
+ expect(sort_options[4]).to eq('Updated date')
expect(sort_options[5]).to eq('Oldest updated')
click_link 'Name, descending'
diff --git a/spec/features/issuables/sorting_list_spec.rb b/spec/features/issuables/sorting_list_spec.rb
index f646cdbd71b..bc40fb713ac 100644
--- a/spec/features/issuables/sorting_list_spec.rb
+++ b/spec/features/issuables/sorting_list_spec.rb
@@ -54,10 +54,10 @@ RSpec.describe 'Sort Issuable List' do
context 'in the "merge requests / merged" tab', :js do
let(:issuable_type) { :merged_merge_request }
- it 'is "last updated"' do
+ it 'is "updated date"' do
visit_merge_requests_with_state(project, 'merged')
- expect(page).to have_button 'Last updated'
+ expect(page).to have_button 'Updated date'
expect(first_merge_request).to include(last_updated_issuable.title)
expect(last_merge_request).to include(first_updated_issuable.title)
end
@@ -66,10 +66,10 @@ RSpec.describe 'Sort Issuable List' do
context 'in the "merge requests / closed" tab', :js do
let(:issuable_type) { :closed_merge_request }
- it 'is "last updated"' do
+ it 'is "updated date"' do
visit_merge_requests_with_state(project, 'closed')
- expect(page).to have_button 'Last updated'
+ expect(page).to have_button 'Updated date'
expect(first_merge_request).to include(last_updated_issuable.title)
expect(last_merge_request).to include(first_updated_issuable.title)
end
@@ -95,7 +95,7 @@ RSpec.describe 'Sort Issuable List' do
visit_merge_requests_with_state(project, 'open')
click_button('Created date')
- click_link('Last updated')
+ click_link('Updated date')
expect(first_merge_request).to include(last_updated_issuable.title)
expect(last_merge_request).to include(first_updated_issuable.title)
@@ -152,10 +152,10 @@ RSpec.describe 'Sort Issuable List' do
context 'in the "issues / closed" tab', :js do
let(:issuable_type) { :closed_issue }
- it 'is "last updated"' do
+ it 'is "updated date"' do
visit_issues_with_state(project, 'closed')
- expect(page).to have_button 'Last updated'
+ expect(page).to have_button 'Updated date'
expect(first_issue).to include(last_updated_issuable.title)
expect(last_issue).to include(first_updated_issuable.title)
end
@@ -195,7 +195,7 @@ RSpec.describe 'Sort Issuable List' do
visit_issues_with_state(project, 'opened')
click_button('Created date')
- click_on('Last updated')
+ click_on('Updated date')
expect(page).to have_css('.issue:first-child', text: last_updated_issuable.title)
expect(page).to have_css('.issue:last-child', text: first_updated_issuable.title)
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index 6d05e553cc7..363d08da024 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -117,7 +117,7 @@ RSpec.describe 'Branches' do
it 'sorts the branches by name', :js do
visit project_branches_filtered_path(project, state: 'all')
- click_button "Last updated" # Open sorting dropdown
+ click_button "Updated date" # Open sorting dropdown
within '[data-testid="branches-dropdown"]' do
find('p', text: 'Name').click
end
@@ -128,7 +128,7 @@ RSpec.describe 'Branches' do
it 'sorts the branches by oldest updated', :js do
visit project_branches_filtered_path(project, state: 'all')
- click_button "Last updated" # Open sorting dropdown
+ click_button "Updated date" # Open sorting dropdown
within '[data-testid="branches-dropdown"]' do
find('p', text: 'Oldest updated').click
end
diff --git a/spec/features/projects/labels/sort_labels_spec.rb b/spec/features/projects/labels/sort_labels_spec.rb
index 83559b816d2..26b3d08253c 100644
--- a/spec/features/projects/labels/sort_labels_spec.rb
+++ b/spec/features/projects/labels/sort_labels_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe 'Sort labels', :js do
expect(sort_options[1]).to eq('Name, descending')
expect(sort_options[2]).to eq('Last created')
expect(sort_options[3]).to eq('Oldest created')
- expect(sort_options[4]).to eq('Last updated')
+ expect(sort_options[4]).to eq('Updated date')
expect(sort_options[5]).to eq('Oldest updated')
click_link 'Name, descending'
diff --git a/spec/features/projects/user_sorts_projects_spec.rb b/spec/features/projects/user_sorts_projects_spec.rb
index 6a5ed49f1a6..71e43467a39 100644
--- a/spec/features/projects/user_sorts_projects_spec.rb
+++ b/spec/features/projects/user_sorts_projects_spec.rb
@@ -41,10 +41,10 @@ RSpec.describe 'User sorts projects and order persists' do
sign_in(user)
visit(explore_projects_path)
find('#sort-projects-dropdown').click
- first(:link, 'Last updated').click
+ first(:link, 'Updated date').click
end
- it_behaves_like "sort order persists across all views", "Last updated", "Last updated"
+ it_behaves_like "sort order persists across all views", 'Updated date', 'Updated date'
end
context 'from dashboard projects' do
diff --git a/spec/features/user_sorts_things_spec.rb b/spec/features/user_sorts_things_spec.rb
index 6eaa620b538..8e6f6a96bd2 100644
--- a/spec/features/user_sorts_things_spec.rb
+++ b/spec/features/user_sorts_things_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe "User sorts things" do
end
it "issues -> project home page -> issues" do
- sort_option = "Last updated"
+ sort_option = 'Updated date'
visit(project_issues_path(project))
@@ -34,7 +34,7 @@ RSpec.describe "User sorts things" do
end
it "issues -> merge requests" do
- sort_option = "Last updated"
+ sort_option = 'Updated date'
visit(project_issues_path(project))
@@ -46,7 +46,7 @@ RSpec.describe "User sorts things" do
end
it "merge requests -> dashboard merge requests" do
- sort_option = "Last updated"
+ sort_option = 'Updated date'
visit(project_merge_requests_path(project))
diff --git a/spec/finders/fork_targets_finder_spec.rb b/spec/finders/fork_targets_finder_spec.rb
index 12f01227af8..fe5b50ef030 100644
--- a/spec/finders/fork_targets_finder_spec.rb
+++ b/spec/finders/fork_targets_finder_spec.rb
@@ -16,7 +16,9 @@ RSpec.describe ForkTargetsFinder do
end
let!(:developer_group) do
- create(:group).tap { |g| g.add_developer(user) }
+ create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS).tap do |g|
+ g.add_developer(user)
+ end
end
let!(:reporter_group) do
@@ -33,11 +35,11 @@ RSpec.describe ForkTargetsFinder do
describe '#execute' do
it 'returns all user manageable namespaces' do
- expect(finder.execute).to match_array([user.namespace, maintained_group, owned_group, project.namespace])
+ expect(finder.execute).to match_array([user.namespace, maintained_group, owned_group, project.namespace, developer_group])
end
it 'returns only groups when only_groups option is passed' do
- expect(finder.execute(only_groups: true)).to match_array([maintained_group, owned_group, project.namespace])
+ expect(finder.execute(only_groups: true)).to match_array([maintained_group, owned_group, project.namespace, developer_group])
end
it 'returns groups relation when only_groups option is passed' do
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
index 40bc6fe6aa5..c193bb08543 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
@@ -90,6 +90,8 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
/>
<!---->
+
+ <!---->
</div>
</div>
</div>
diff --git a/spec/frontend/vue_shared/components/markdown/field_spec.js b/spec/frontend/vue_shared/components/markdown/field_spec.js
index 76e1a1162ad..0d90ca7f1f6 100644
--- a/spec/frontend/vue_shared/components/markdown/field_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/field_spec.js
@@ -1,4 +1,5 @@
import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import AxiosMockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import { TEST_HOST, FIXTURES_PATH } from 'spec/test_constants';
@@ -242,6 +243,41 @@ describe('Markdown field component', () => {
expect(dropzoneSpy).toHaveBeenCalled();
});
+
+ describe('mentioning all users', () => {
+ const users = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map((i) => `user_${i}`);
+
+ it('shows warning on mention of all users', async () => {
+ axiosMock.onPost(markdownPreviewPath).reply(200, { references: { users } });
+
+ subject.setProps({ textareaValue: 'hello @all' });
+
+ await axios.waitFor(markdownPreviewPath).then(() => {
+ expect(subject.text()).toContain(
+ 'You are about to add 11 people to the discussion. They will all receive a notification.',
+ );
+ });
+ });
+
+ it('removes warning when all mention is removed', async () => {
+ axiosMock.onPost(markdownPreviewPath).reply(200, { references: { users } });
+
+ subject.setProps({ textareaValue: 'hello @all' });
+
+ await axios.waitFor(markdownPreviewPath);
+
+ jest.spyOn(axios, 'post');
+
+ subject.setProps({ textareaValue: 'hello @allan' });
+
+ await nextTick();
+
+ expect(axios.post).not.toHaveBeenCalled();
+ expect(subject.text()).not.toContain(
+ 'You are about to add 11 people to the discussion. They will all receive a notification.',
+ );
+ });
+ });
});
});
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 457c9c0f5de..40cfdafc9ac 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -641,7 +641,7 @@ RSpec.describe SearchHelper do
}
},
{
- title: _('Last updated'),
+ title: _('Updated date'),
sortable: true,
sortParam: {
asc: 'updated_asc',
diff --git a/spec/lib/error_tracking/collector/payload_validator_spec.rb b/spec/lib/error_tracking/collector/payload_validator_spec.rb
index a7a3308eb8d..94708f63bf4 100644
--- a/spec/lib/error_tracking/collector/payload_validator_spec.rb
+++ b/spec/lib/error_tracking/collector/payload_validator_spec.rb
@@ -18,43 +18,25 @@ RSpec.describe ErrorTracking::Collector::PayloadValidator do
end
end
- context 'ruby payload' do
- let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/parsed_event.json')) }
-
- it_behaves_like 'valid payload'
- end
-
- context 'python payload' do
- let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/python_event.json')) }
-
- it_behaves_like 'valid payload'
- end
-
- context 'python payload in repl' do
- let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/python_event_repl.json')) }
-
- it_behaves_like 'valid payload'
- end
-
- context 'browser payload' do
- let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/browser_event.json')) }
-
- it_behaves_like 'valid payload'
- end
+ context 'with event fixtures' do
+ where(:event_fixture) do
+ Dir.glob(Rails.root.join('spec/fixtures/error_tracking/*event*.json'))
+ end
- context 'go payload' do
- let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/go_parsed_event.json')) }
+ with_them do
+ let(:payload) { Gitlab::Json.parse(fixture_file(event_fixture)) }
- it_behaves_like 'valid payload'
+ it_behaves_like 'valid payload'
+ end
end
- context 'empty payload' do
+ context 'when empty' do
let(:payload) { '' }
it_behaves_like 'invalid payload'
end
- context 'invalid payload' do
+ context 'when invalid' do
let(:payload) { { 'foo' => 'bar' } }
it_behaves_like 'invalid payload'
diff --git a/spec/lib/gitlab/exceptions_app_spec.rb b/spec/lib/gitlab/exceptions_app_spec.rb
new file mode 100644
index 00000000000..6b726a044a8
--- /dev/null
+++ b/spec/lib/gitlab/exceptions_app_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ExceptionsApp, type: :request do
+ describe '.call' do
+ let(:exceptions_app) { described_class.new(Rails.public_path) }
+ let(:app) { ActionDispatch::ShowExceptions.new(error_raiser, exceptions_app) }
+
+ before do
+ @app = app
+ end
+
+ context 'for a 500 error' do
+ let(:error_raiser) { proc { raise 'an unhandled error' } }
+
+ context 'for an HTML request' do
+ it 'fills in the request ID' do
+ get '/', env: { 'action_dispatch.request_id' => 'foo' }
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(response).to have_header('X-Gitlab-Custom-Error')
+ expect(response.body).to include('Request ID: <code>foo</code>')
+ end
+
+ it 'HTML-escapes the request ID' do
+ get '/', env: { 'action_dispatch.request_id' => '<b>foo</b>' }
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(response).to have_header('X-Gitlab-Custom-Error')
+ expect(response.body).to include('Request ID: <code>&lt;b&gt;foo&lt;/b&gt;</code>')
+ end
+
+ it 'returns an empty 500 when the 500.html page cannot be found' do
+ allow(File).to receive(:exist?).and_return(false)
+
+ get '/', env: { 'action_dispatch.request_id' => 'foo' }
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(response).not_to have_header('X-Gitlab-Custom-Error')
+ expect(response.body).to be_empty
+ end
+ end
+
+ context 'for a JSON request' do
+ it 'does not include the request ID' do
+ get '/', env: { 'action_dispatch.request_id' => 'foo' }, as: :json
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(response).not_to have_header('X-Gitlab-Custom-Error')
+ expect(response.body).not_to include('foo')
+ end
+ end
+ end
+
+ context 'for a 404 error' do
+ let(:error_raiser) { proc { raise AbstractController::ActionNotFound } }
+
+ it 'returns a 404 response that does not include the request ID' do
+ get '/', env: { 'action_dispatch.request_id' => 'foo' }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).not_to have_header('X-Gitlab-Custom-Error')
+ expect(response.body).not_to include('foo')
+ end
+ end
+ end
+end
diff --git a/spec/models/integrations/asana_spec.rb b/spec/models/integrations/asana_spec.rb
index f7e7eb1b0ae..b6602964182 100644
--- a/spec/models/integrations/asana_spec.rb
+++ b/spec/models/integrations/asana_spec.rb
@@ -14,27 +14,29 @@ RSpec.describe Integrations::Asana do
end
describe 'Execute' do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+
let(:gid) { "123456789ABCD" }
+ let(:asana_task) { double(::Asana::Resources::Task) }
+ let(:asana_integration) { described_class.new }
- def create_data_for_commits(*messages)
+ let(:data) do
{
object_kind: 'push',
ref: 'master',
user_name: user.name,
- commits: messages.map do |m|
+ commits: [
{
- message: m,
+ message: message,
url: 'https://gitlab.com/'
}
- end
+ ]
}
end
before do
- @asana = described_class.new
- allow(@asana).to receive_messages(
+ allow(asana_integration).to receive_messages(
project: project,
project_id: project.id,
api_key: 'verySecret',
@@ -42,67 +44,79 @@ RSpec.describe Integrations::Asana do
)
end
- it 'calls Asana integration to create a story' do
- data = create_data_for_commits("Message from commit. related to ##{gid}")
- expected_message = "#{data[:user_name]} pushed to branch #{data[:ref]} of #{project.full_name} ( #{data[:commits][0][:url]} ): #{data[:commits][0][:message]}"
+ subject(:execute_integration) { asana_integration.execute(data) }
+
+ context 'when creating a story' do
+ let(:message) { "Message from commit. related to ##{gid}" }
+ let(:expected_message) do
+ "#{user.name} pushed to branch master of #{project.full_name} ( https://gitlab.com/ ): #{message}"
+ end
- d1 = double('Asana::Resources::Task')
- expect(d1).to receive(:add_comment).with(text: expected_message)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, gid).once.and_return(d1)
+ it 'calls Asana integration to create a story' do
+ expect(asana_task).to receive(:add_comment).with(text: expected_message)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, gid).once.and_return(asana_task)
- @asana.execute(data)
+ execute_integration
+ end
end
- it 'calls Asana integration to create a story and close a task' do
- data = create_data_for_commits('fix #456789')
- d1 = double('Asana::Resources::Task')
- expect(d1).to receive(:add_comment)
- expect(d1).to receive(:update).with(completed: true)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '456789').once.and_return(d1)
+ context 'when creating a story and closing a task' do
+ let(:message) { 'fix #456789' }
- @asana.execute(data)
+ it 'calls Asana integration to create a story and close a task' do
+ expect(asana_task).to receive(:add_comment)
+ expect(asana_task).to receive(:update).with(completed: true)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '456789').once.and_return(asana_task)
+
+ execute_integration
+ end
end
- it 'is able to close via url' do
- data = create_data_for_commits('closes https://app.asana.com/19292/956299/42')
- d1 = double('Asana::Resources::Task')
- expect(d1).to receive(:add_comment)
- expect(d1).to receive(:update).with(completed: true)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '42').once.and_return(d1)
+ context 'when closing via url' do
+ let(:message) { 'closes https://app.asana.com/19292/956299/42' }
- @asana.execute(data)
+ it 'calls Asana integration to close via url' do
+ expect(asana_task).to receive(:add_comment)
+ expect(asana_task).to receive(:update).with(completed: true)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '42').once.and_return(asana_task)
+
+ execute_integration
+ end
end
- it 'allows multiple matches per line' do
- message = <<-EOF
- minor bigfix, refactoring, fixed #123 and Closes #456 work on #789
- ref https://app.asana.com/19292/956299/42 and closing https://app.asana.com/19292/956299/12
- EOF
- data = create_data_for_commits(message)
- d1 = double('Asana::Resources::Task')
- expect(d1).to receive(:add_comment)
- expect(d1).to receive(:update).with(completed: true)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '123').once.and_return(d1)
-
- d2 = double('Asana::Resources::Task')
- expect(d2).to receive(:add_comment)
- expect(d2).to receive(:update).with(completed: true)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '456').once.and_return(d2)
-
- d3 = double('Asana::Resources::Task')
- expect(d3).to receive(:add_comment)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '789').once.and_return(d3)
-
- d4 = double('Asana::Resources::Task')
- expect(d4).to receive(:add_comment)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '42').once.and_return(d4)
-
- d5 = double('Asana::Resources::Task')
- expect(d5).to receive(:add_comment)
- expect(d5).to receive(:update).with(completed: true)
- expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '12').once.and_return(d5)
-
- @asana.execute(data)
+ context 'with multiple matches per line' do
+ let(:message) do
+ <<-EOF
+ minor bigfix, refactoring, fixed #123 and Closes #456 work on #789
+ ref https://app.asana.com/19292/956299/42 and closing https://app.asana.com/19292/956299/12
+ EOF
+ end
+
+ it 'allows multiple matches per line' do
+ expect(asana_task).to receive(:add_comment)
+ expect(asana_task).to receive(:update).with(completed: true)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '123').once.and_return(asana_task)
+
+ asana_task_2 = double(Asana::Resources::Task)
+ expect(asana_task_2).to receive(:add_comment)
+ expect(asana_task_2).to receive(:update).with(completed: true)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '456').once.and_return(asana_task_2)
+
+ asana_task_3 = double(Asana::Resources::Task)
+ expect(asana_task_3).to receive(:add_comment)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '789').once.and_return(asana_task_3)
+
+ asana_task_4 = double(Asana::Resources::Task)
+ expect(asana_task_4).to receive(:add_comment)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '42').once.and_return(asana_task_4)
+
+ asana_task_5 = double(Asana::Resources::Task)
+ expect(asana_task_5).to receive(:add_comment)
+ expect(asana_task_5).to receive(:update).with(completed: true)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '12').once.and_return(asana_task_5)
+
+ execute_integration
+ end
end
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 93039a2118a..6593461f807 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2055,7 +2055,7 @@ RSpec.describe User do
it { expect(user.authorized_groups).to eq([group]) }
it { expect(user.owned_groups).to eq([group]) }
it { expect(user.namespaces).to contain_exactly(user.namespace, group) }
- it { expect(user.manageable_namespaces).to contain_exactly(user.namespace, group) }
+ it { expect(user.forkable_namespaces).to contain_exactly(user.namespace, group) }
context 'with owned groups only' do
before do
@@ -2069,9 +2069,12 @@ RSpec.describe User do
context 'with child groups' do
let!(:subgroup) { create(:group, parent: group) }
- describe '#manageable_namespaces' do
- it 'includes all the namespaces the user can manage' do
- expect(user.manageable_namespaces).to contain_exactly(user.namespace, group, subgroup)
+ describe '#forkable_namespaces' do
+ it 'includes all the namespaces the user can fork into' do
+ developer_group = create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
+ developer_group.add_developer(user)
+
+ expect(user.forkable_namespaces).to contain_exactly(user.namespace, group, subgroup, developer_group)
end
end
diff --git a/spec/services/error_tracking/collect_error_service_spec.rb b/spec/services/error_tracking/collect_error_service_spec.rb
index facb7b01e61..2b16612dac3 100644
--- a/spec/services/error_tracking/collect_error_service_spec.rb
+++ b/spec/services/error_tracking/collect_error_service_spec.rb
@@ -4,8 +4,9 @@ require 'spec_helper'
RSpec.describe ErrorTracking::CollectErrorService do
let_it_be(:project) { create(:project) }
- let_it_be(:parsed_event_file) { 'error_tracking/parsed_event.json' }
- let_it_be(:parsed_event) { Gitlab::Json.parse(fixture_file(parsed_event_file)) }
+
+ let(:parsed_event_file) { 'error_tracking/parsed_event.json' }
+ let(:parsed_event) { parse_valid_event(parsed_event_file) }
subject { described_class.new(project, nil, event: parsed_event) }
@@ -43,7 +44,7 @@ RSpec.describe ErrorTracking::CollectErrorService do
end
context 'python sdk event' do
- let(:parsed_event) { Gitlab::Json.parse(fixture_file('error_tracking/python_event.json')) }
+ let(:parsed_event_file) { 'error_tracking/python_event.json' }
it 'creates a valid event' do
expect { subject.execute }.to change { ErrorTracking::ErrorEvent.count }.by(1)
@@ -75,7 +76,7 @@ RSpec.describe ErrorTracking::CollectErrorService do
end
context 'go payload' do
- let(:parsed_event) { Gitlab::Json.parse(fixture_file('error_tracking/go_parsed_event.json')) }
+ let(:parsed_event_file) { 'error_tracking/go_parsed_event.json' }
it 'has correct values set' do
subject.execute
@@ -94,7 +95,7 @@ RSpec.describe ErrorTracking::CollectErrorService do
end
context 'with two exceptions' do
- let(:parsed_event) { Gitlab::Json.parse(fixture_file('error_tracking/go_two_exception_event.json')) }
+ let(:parsed_event_file) { 'error_tracking/go_two_exception_event.json' }
it 'reports using second exception', :aggregate_failures do
subject.execute
@@ -113,4 +114,17 @@ RSpec.describe ErrorTracking::CollectErrorService do
end
end
end
+
+ private
+
+ def parse_valid_event(parsed_event_file)
+ parsed_event = Gitlab::Json.parse(fixture_file(parsed_event_file))
+
+ validator = ErrorTracking::Collector::PayloadValidator.new
+ # This a precondition for all specs to verify that
+ # submitted JSON payload is valid.
+ expect(validator).to be_valid(parsed_event)
+
+ parsed_event
+ end
end
diff --git a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
index 96d781578e3..2a976fb7421 100644
--- a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
+RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name|
include StubRequests
- let(:chat_service) { described_class.new }
+ let(:chat_integration) { described_class.new }
let(:webhook_url) { 'https://example.gitlab.com' }
def execute_with_options(options)
@@ -17,7 +17,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
end
describe 'Validations' do
- context 'when service is active' do
+ context 'when integration is active' do
before do
subject.active = true
end
@@ -26,7 +26,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
it_behaves_like 'issue tracker integration URL attribute', :webhook
end
- context 'when service is inactive' do
+ context 'when integration is inactive' do
before do
subject.active = false
end
@@ -35,9 +35,9 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
end
end
- shared_examples "triggered #{service_name} service" do |event_type: nil, branches_to_be_notified: nil|
+ shared_examples "triggered #{integration_name} integration" do |event_type: nil, branches_to_be_notified: nil|
before do
- chat_service.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
+ chat_integration.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
end
let!(:stubbed_resolved_hostname) do
@@ -45,14 +45,14 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
end
it "notifies about #{event_type} events" do
- chat_service.execute(data)
+ chat_integration.execute(data)
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname)
end
end
- shared_examples "untriggered #{service_name} service" do |event_type: nil, branches_to_be_notified: nil|
+ shared_examples "untriggered #{integration_name} integration" do |event_type: nil, branches_to_be_notified: nil|
before do
- chat_service.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
+ chat_integration.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
end
let!(:stubbed_resolved_hostname) do
@@ -60,7 +60,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
end
it "notifies about #{event_type} events" do
- chat_service.execute(data)
+ chat_integration.execute(data)
expect(WebMock).not_to have_requested(:post, stubbed_resolved_hostname)
end
end
@@ -69,50 +69,50 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let_it_be(:project) { create(:project, :repository, :wiki_repo) }
let_it_be(:user) { create(:user) }
- let(:chat_service) { described_class.new( { project: project, webhook: webhook_url, branches_to_be_notified: 'all' }.merge(chat_service_params)) }
- let(:chat_service_params) { {} }
+ let(:chat_integration) { described_class.new( { project: project, webhook: webhook_url, branches_to_be_notified: 'all' }.merge(chat_integration_params)) }
+ let(:chat_integration_params) { {} }
let(:data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
let!(:stubbed_resolved_hostname) do
stub_full_request(webhook_url, method: :post).request_pattern.uri_pattern.to_s
end
- subject(:execute_service) { chat_service.execute(data) }
+ subject(:execute_integration) { chat_integration.execute(data) }
- shared_examples 'calls the service API with the event message' do |event_message|
+ shared_examples 'calls the integration API with the event message' do |event_message|
specify do
expect_next_instance_of(::Slack::Messenger) do |messenger|
expect(messenger).to receive(:ping).with(event_message, anything).and_call_original
end
- execute_service
+ execute_integration
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname).once
end
end
context 'with username for slack configured' do
- let(:chat_service_params) { { username: 'slack_username' } }
+ let(:chat_integration_params) { { username: 'slack_username' } }
it 'uses the username as an option' do
expect(::Slack::Messenger).to execute_with_options(username: 'slack_username')
- execute_service
+ execute_integration
end
end
context 'push events' do
let(:data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
- it_behaves_like 'calls the service API with the event message', /pushed to branch/
+ it_behaves_like 'calls the integration API with the event message', /pushed to branch/
context 'with event channel' do
- let(:chat_service_params) { { push_channel: 'random' } }
+ let(:chat_integration_params) { { push_channel: 'random' } }
it 'uses the right channel for push event' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
- execute_service
+ execute_integration
end
end
end
@@ -123,7 +123,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:ref) { 'refs/tags/v1.1.0' }
let(:data) { Git::TagHooksService.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref }).send(:push_data) }
- it_behaves_like 'calls the service API with the event message', /pushed new tag/
+ it_behaves_like 'calls the integration API with the event message', /pushed new tag/
end
context 'issue events' do
@@ -131,15 +131,15 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { issue.to_hook_data(user) }
- it_behaves_like 'calls the service API with the event message', /Issue (.*?) opened by/
+ it_behaves_like 'calls the integration API with the event message', /Issue (.*?) opened by/
context 'whith event channel' do
- let(:chat_service_params) { { issue_channel: 'random' } }
+ let(:chat_integration_params) { { issue_channel: 'random' } }
it 'uses the right channel for issue event' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
- execute_service
+ execute_integration
end
context 'for confidential issues' do
@@ -150,16 +150,16 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
it 'falls back to issue channel' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
- execute_service
+ execute_integration
end
context 'and confidential_issue_channel is defined' do
- let(:chat_service_params) { { issue_channel: 'random', confidential_issue_channel: 'confidential' } }
+ let(:chat_integration_params) { { issue_channel: 'random', confidential_issue_channel: 'confidential' } }
it 'uses the confidential issue channel when it is defined' do
expect(::Slack::Messenger).to execute_with_options(channel: ['confidential'])
- execute_service
+ execute_integration
end
end
end
@@ -171,15 +171,15 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { merge_request.to_hook_data(user) }
- it_behaves_like 'calls the service API with the event message', /opened merge request/
+ it_behaves_like 'calls the integration API with the event message', /opened merge request/
context 'with event channel' do
- let(:chat_service_params) { { merge_request_channel: 'random' } }
+ let(:chat_integration_params) { { merge_request_channel: 'random' } }
it 'uses the right channel for merge request event' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
- execute_service
+ execute_integration
end
end
end
@@ -189,15 +189,15 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
- it_behaves_like 'calls the service API with the event message', %r{ created (.*?)wikis/(.*?)|wiki page> in}
+ it_behaves_like 'calls the integration API with the event message', %r{ created (.*?)wikis/(.*?)|wiki page> in}
context 'with event channel' do
- let(:chat_service_params) { { wiki_page_channel: 'random' } }
+ let(:chat_integration_params) { { wiki_page_channel: 'random' } }
it 'uses the right channel for wiki event' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
- execute_service
+ execute_integration
end
end
end
@@ -207,7 +207,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, Time.current) }
- it_behaves_like 'calls the service API with the event message', /Deploy to (.*?) created/
+ it_behaves_like 'calls the integration API with the event message', /Deploy to (.*?) created/
end
context 'note event' do
@@ -215,15 +215,15 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Note.build(issue_note, user) }
- it_behaves_like 'calls the service API with the event message', /commented on issue/
+ it_behaves_like 'calls the integration API with the event message', /commented on issue/
context 'with event channel' do
- let(:chat_service_params) { { note_channel: 'random' } }
+ let(:chat_integration_params) { { note_channel: 'random' } }
it 'uses the right channel' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
- execute_service
+ execute_integration
end
context 'for confidential notes' do
@@ -234,16 +234,16 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
it 'falls back to note channel' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
- execute_service
+ execute_integration
end
context 'and confidential_note_channel is defined' do
- let(:chat_service_params) { { note_channel: 'random', confidential_note_channel: 'confidential' } }
+ let(:chat_integration_params) { { note_channel: 'random', confidential_note_channel: 'confidential' } }
it 'uses confidential channel' do
expect(::Slack::Messenger).to execute_with_options(channel: ['confidential'])
- execute_service
+ execute_integration
end
end
end
@@ -256,7 +256,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:project) { create(:project, :repository, creator: user) }
before do
- allow(chat_service).to receive_messages(
+ allow(chat_integration).to receive_messages(
project: project,
service_hook: true,
webhook: webhook_url
@@ -283,23 +283,23 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
)
end
- it_behaves_like "triggered #{service_name} service", event_type: "push"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push"
end
context 'notification enabled only for default branch' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "default"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "untriggered #{service_name} service", event_type: "push", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "all"
end
end
@@ -325,23 +325,23 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
)
end
- it_behaves_like "triggered #{service_name} service", event_type: "push"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push"
end
context 'notification enabled only for default branch' do
- it_behaves_like "untriggered #{service_name} service", event_type: "push", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "all"
end
end
@@ -367,23 +367,23 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
)
end
- it_behaves_like "triggered #{service_name} service", event_type: "push"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push"
end
context 'notification enabled only for default branch' do
- it_behaves_like "untriggered #{service_name} service", event_type: "push", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "all"
end
end
@@ -405,23 +405,23 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
)
end
- it_behaves_like "triggered #{service_name} service", event_type: "push"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push"
end
context 'notification enabled only for default branch' do
- it_behaves_like "untriggered #{service_name} service", event_type: "push", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "untriggered #{service_name} service", event_type: "push", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "untriggered #{service_name} service", event_type: "push", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "push", branches_to_be_notified: "all"
end
end
end
@@ -431,7 +431,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:project) { create(:project, :repository, creator: user) }
before do
- allow(chat_service).to receive_messages(
+ allow(chat_integration).to receive_messages(
project: project,
service_hook: true,
webhook: webhook_url
@@ -452,7 +452,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
Gitlab::DataBuilder::Note.build(commit_note, user)
end
- it_behaves_like "triggered #{service_name} service", event_type: "commit comment"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "commit comment"
end
context 'when merge request comment event executed' do
@@ -465,7 +465,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
Gitlab::DataBuilder::Note.build(merge_request_note, user)
end
- it_behaves_like "triggered #{service_name} service", event_type: "merge request comment"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "merge request comment"
end
context 'when issue comment event executed' do
@@ -478,7 +478,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
Gitlab::DataBuilder::Note.build(issue_note, user)
end
- it_behaves_like "triggered #{service_name} service", event_type: "issue comment"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "issue comment"
end
context 'when snippet comment event executed' do
@@ -491,7 +491,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
Gitlab::DataBuilder::Note.build(snippet_note, user)
end
- it_behaves_like "triggered #{service_name} service", event_type: "snippet comment"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "snippet comment"
end
end
@@ -505,7 +505,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
end
before do
- allow(chat_service).to receive_messages(
+ allow(chat_integration).to receive_messages(
project: project,
service_hook: true,
webhook: webhook_url
@@ -519,15 +519,15 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
context 'with default to notify_only_broken_pipelines' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline"
end
context 'with setting notify_only_broken_pipelines to false' do
before do
- chat_service.notify_only_broken_pipelines = false
+ chat_integration.notify_only_broken_pipelines = false
end
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline"
end
end
@@ -542,19 +542,19 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
context 'notification enabled only for default branch' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "all"
end
end
@@ -572,19 +572,19 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
context 'notification enabled only for default branch' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "all"
end
end
@@ -602,19 +602,19 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
context 'notification enabled only for default branch' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "all"
end
end
@@ -628,19 +628,19 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
context 'notification enabled only for default branch' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "all"
end
end
end
@@ -657,7 +657,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, Time.now) }
before do
- allow(chat_service).to receive_messages(
+ allow(chat_integration).to receive_messages(
project: project,
service_hook: true,
webhook: webhook_url
@@ -666,7 +666,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
stub_full_request(webhook_url, method: :post)
end
- it_behaves_like "triggered #{service_name} service", event_type: "deployment"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "deployment"
context 'on a protected branch' do
before do
@@ -678,19 +678,19 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
end
context 'notification enabled only for default branch' do
- it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default"
end
context 'notification enabled only for protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "protected"
end
context 'notification enabled only for default and protected branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
end
context 'notification enabled for all branches' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "all"
end
context 'when chat_notification_deployment_protected_branch_filter is disabled' do
@@ -699,7 +699,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
end
context 'notification enabled only for default branch' do
- it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default"
+ it_behaves_like "triggered #{integration_name} integration", event_type: "pipeline", branches_to_be_notified: "default"
end
end
end