summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop.yml2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue13
-rw-r--r--app/services/projects/prometheus/metrics/base_service.rb48
-rw-r--r--app/services/projects/prometheus/metrics/destroy_service.rb14
-rw-r--r--app/services/projects/prometheus/metrics/update_service.rb29
-rw-r--r--app/views/projects/network/show.html.haml3
-rw-r--r--changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-projects-network.yml5
-rw-r--r--changelogs/unreleased/closing-issue-spec.yml5
-rw-r--r--changelogs/unreleased/merge-requests.yml5
-rw-r--r--db/migrate/20200403184110_add_partial_index_on_id_to_ci_job_artifacts.rb18
-rw-r--r--db/migrate/20200403185127_add_partial_index_on_id_to_lfs_objects.rb18
-rw-r--r--db/migrate/20200403185422_add_partial_index_on_id_to_uploads.rb18
-rw-r--r--db/structure.sql9
-rw-r--r--doc/ci/variables/predefined_variables.md2
-rw-r--r--doc/development/code_review.md2
-rw-r--r--doc/development/documentation/index.md54
-rw-r--r--doc/development/documentation/styleguide.md2
-rw-r--r--lib/gitlab/database/batch_count.rb4
-rw-r--r--lib/gitlab/usage_data.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb2
-rw-r--r--spec/features/projects/services/user_activates_asana_spec.rb19
-rw-r--r--spec/features/projects/services/user_activates_assembla_spec.rb17
-rw-r--r--spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb19
-rw-r--r--spec/features/projects/services/user_activates_emails_on_push_spec.rb19
-rw-r--r--spec/features/projects/services/user_activates_flowdock_spec.rb19
-rw-r--r--spec/features/projects/services/user_activates_hipchat_spec.rb32
-rw-r--r--spec/features/projects/services/user_activates_irker_spec.rb19
-rw-r--r--spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb17
-rw-r--r--spec/features/projects/services/user_activates_packagist_spec.rb17
-rw-r--r--spec/features/projects/services/user_activates_pivotaltracker_spec.rb17
-rw-r--r--spec/features/projects/services/user_activates_prometheus_spec.rb14
-rw-r--r--spec/features/projects/services/user_activates_pushover_spec.rb17
-rw-r--r--spec/features/projects/services/user_activates_slack_notifications_spec.rb22
-rw-r--r--spec/features/projects/services/user_views_services_spec.rb12
-rw-r--r--spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js22
-rw-r--r--spec/frontend/fixtures/merge_requests.rb2
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb4
-rw-r--r--spec/lib/gitlab/database/batch_count_spec.rb46
-rw-r--r--spec/services/projects/prometheus/metrics/destroy_service_spec.rb28
-rw-r--r--spec/services/projects/prometheus/metrics/update_service_spec.rb44
-rw-r--r--spec/support/shared_contexts/project_service_shared_context.rb32
42 files changed, 457 insertions, 240 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index fb6933d1883..c6046224e4e 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -392,9 +392,7 @@ RSpec/RepeatedExample:
- 'spec/features/merge_request/user_posts_diff_notes_spec.rb'
- 'spec/features/projects/files/template_type_dropdown_spec.rb'
- 'spec/finders/environments_finder_spec.rb'
- - 'spec/frontend/fixtures/merge_requests.rb'
- 'spec/helpers/users_helper_spec.rb'
- - 'spec/lib/gitlab/closing_issue_extractor_spec.rb'
- 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
- 'spec/services/notification_service_spec.rb'
- 'spec/services/web_hook_service_spec.rb'
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 0ac74451100..5239b90e3c2 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-8.29.0
+8.30.0
diff --git a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
index e191bfd79cb..5023496e2c3 100644
--- a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
+++ b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
@@ -23,6 +23,8 @@ const popoverStates = {
},
};
export default {
+ dismissTrackValue: 10,
+ clickTrackValue: 'click_button',
components: {
GlPopover,
GlSprintf,
@@ -109,7 +111,16 @@ export default {
<template #title>
<span v-html="suggestTitle"></span>
<span class="ml-auto">
- <gl-deprecated-button :aria-label="__('Close')" class="btn-blank" @click="onDismiss">
+ <gl-deprecated-button
+ :aria-label="__('Close')"
+ class="btn-blank"
+ name="dismiss"
+ :data-track-property="humanAccess"
+ :data-track-value="$options.dismissTrackValue"
+ :data-track-event="$options.clickTrackValue"
+ :data-track-label="trackLabel"
+ @click="onDismiss"
+ >
<gl-icon name="close" aria-hidden="true" />
</gl-deprecated-button>
</span>
diff --git a/app/services/projects/prometheus/metrics/base_service.rb b/app/services/projects/prometheus/metrics/base_service.rb
new file mode 100644
index 00000000000..be1783dde70
--- /dev/null
+++ b/app/services/projects/prometheus/metrics/base_service.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Projects
+ module Prometheus
+ module Metrics
+ class BaseService
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(metric, params = {})
+ @metric = metric
+ @project = metric.project
+ @params = params.dup
+ end
+
+ protected
+
+ attr_reader :metric, :project, :params
+
+ def application
+ alert.environment.cluster_prometheus_adapter
+ end
+
+ def schedule_alert_update
+ return unless alert
+ return unless alert.environment
+
+ ::Clusters::Applications::ScheduleUpdateService.new(
+ alert.environment.cluster_prometheus_adapter, project).execute
+ end
+
+ def alert
+ strong_memoize(:alert) { find_alert(metric) }
+ end
+
+ def find_alert(metric)
+ Projects::Prometheus::AlertsFinder
+ .new(project: project, metric: metric)
+ .execute
+ .first
+ end
+
+ def has_alert?
+ alert.present?
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/projects/prometheus/metrics/destroy_service.rb b/app/services/projects/prometheus/metrics/destroy_service.rb
new file mode 100644
index 00000000000..6a46eb5516c
--- /dev/null
+++ b/app/services/projects/prometheus/metrics/destroy_service.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Projects
+ module Prometheus
+ module Metrics
+ class DestroyService < Metrics::BaseService
+ def execute
+ schedule_alert_update if has_alert?
+ metric.destroy
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/projects/prometheus/metrics/update_service.rb b/app/services/projects/prometheus/metrics/update_service.rb
new file mode 100644
index 00000000000..9b51f4ab47d
--- /dev/null
+++ b/app/services/projects/prometheus/metrics/update_service.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Projects
+ module Prometheus
+ module Metrics
+ class UpdateService < Metrics::BaseService
+ def execute
+ metric.update!(params)
+ schedule_alert_update if requires_alert_update?
+ metric
+ end
+
+ private
+
+ def requires_alert_update?
+ has_alert? && (changing_title? || changing_query?)
+ end
+
+ def changing_title?
+ metric.previous_changes.include?(:title)
+ end
+
+ def changing_query?
+ metric.previous_changes.include?(:query)
+ end
+ end
+ end
+ end
+end
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index 2d3f9116703..6821453cffa 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -16,4 +16,5 @@
- if @commit
.network-graph{ data: { url: @url, commit_url: @commit_url, ref: @ref, commit_id: @commit.id } }
- = spinner nil, true
+ .text-center.prepend-top-default
+ .spinner.spinner-md
diff --git a/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-projects-network.yml b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-projects-network.yml
new file mode 100644
index 00000000000..31d3ad263c2
--- /dev/null
+++ b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-projects-network.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate .fa-spinner to .spinner for app/views/projects/network
+merge_request: 25050
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/closing-issue-spec.yml b/changelogs/unreleased/closing-issue-spec.yml
new file mode 100644
index 00000000000..fb3a6217c47
--- /dev/null
+++ b/changelogs/unreleased/closing-issue-spec.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicate spec from closing issue spec
+merge_request: 28803
+author: Rajendra Kadam
+type: added
diff --git a/changelogs/unreleased/merge-requests.yml b/changelogs/unreleased/merge-requests.yml
new file mode 100644
index 00000000000..c19766422fe
--- /dev/null
+++ b/changelogs/unreleased/merge-requests.yml
@@ -0,0 +1,5 @@
+---
+title: Fix duplciate spec in merge requests
+merge_request: 28856
+author: Rajendra Kadam
+type: added
diff --git a/db/migrate/20200403184110_add_partial_index_on_id_to_ci_job_artifacts.rb b/db/migrate/20200403184110_add_partial_index_on_id_to_ci_job_artifacts.rb
new file mode 100644
index 00000000000..f5f9f167df3
--- /dev/null
+++ b/db/migrate/20200403184110_add_partial_index_on_id_to_ci_job_artifacts.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddPartialIndexOnIdToCiJobArtifacts < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_ci_job_artifacts_file_store_is_null'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_job_artifacts, :id, where: 'file_store IS NULL', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :ci_job_artifacts, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20200403185127_add_partial_index_on_id_to_lfs_objects.rb b/db/migrate/20200403185127_add_partial_index_on_id_to_lfs_objects.rb
new file mode 100644
index 00000000000..e72bb37eb0e
--- /dev/null
+++ b/db/migrate/20200403185127_add_partial_index_on_id_to_lfs_objects.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddPartialIndexOnIdToLfsObjects < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_lfs_objects_file_store_is_null'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :lfs_objects, :id, where: 'file_store IS NULL', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :lfs_objects, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20200403185422_add_partial_index_on_id_to_uploads.rb b/db/migrate/20200403185422_add_partial_index_on_id_to_uploads.rb
new file mode 100644
index 00000000000..e5b532bad61
--- /dev/null
+++ b/db/migrate/20200403185422_add_partial_index_on_id_to_uploads.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddPartialIndexOnIdToUploads < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_uploads_store_is_null'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :uploads, :id, where: 'store IS NULL', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :uploads, INDEX_NAME
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 25855aeadc0..ef3319df364 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -8708,6 +8708,8 @@ CREATE INDEX index_ci_daily_report_results_on_last_pipeline_id ON public.ci_dail
CREATE UNIQUE INDEX index_ci_group_variables_on_group_id_and_key ON public.ci_group_variables USING btree (group_id, key);
+CREATE INDEX index_ci_job_artifacts_file_store_is_null ON public.ci_job_artifacts USING btree (id) WHERE (file_store IS NULL);
+
CREATE INDEX index_ci_job_artifacts_on_expire_at_and_job_id ON public.ci_job_artifacts USING btree (expire_at, job_id);
CREATE INDEX index_ci_job_artifacts_on_file_store ON public.ci_job_artifacts USING btree (file_store);
@@ -9328,6 +9330,8 @@ CREATE UNIQUE INDEX index_lfs_file_locks_on_project_id_and_path ON public.lfs_fi
CREATE INDEX index_lfs_file_locks_on_user_id ON public.lfs_file_locks USING btree (user_id);
+CREATE INDEX index_lfs_objects_file_store_is_null ON public.lfs_objects USING btree (id) WHERE (file_store IS NULL);
+
CREATE INDEX index_lfs_objects_on_file_store ON public.lfs_objects USING btree (file_store);
CREATE UNIQUE INDEX index_lfs_objects_on_oid ON public.lfs_objects USING btree (oid);
@@ -10094,6 +10098,8 @@ CREATE INDEX index_uploads_on_store ON public.uploads USING btree (store);
CREATE INDEX index_uploads_on_uploader_and_path ON public.uploads USING btree (uploader, path);
+CREATE INDEX index_uploads_store_is_null ON public.uploads USING btree (id) WHERE (store IS NULL);
+
CREATE INDEX index_user_agent_details_on_subject_id_and_subject_type ON public.user_agent_details USING btree (subject_id, subject_type);
CREATE INDEX index_user_callouts_on_user_id ON public.user_callouts USING btree (user_id);
@@ -12929,5 +12935,8 @@ COPY "schema_migrations" (version) FROM STDIN;
20200330123739
20200330132913
20200331220930
+20200403184110
+20200403185127
+20200403185422
\.
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 835699359bf..8b8eeb83d16 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -89,7 +89,7 @@ future GitLab releases.**
| `CI_PAGES_URL` | 11.8 | all | URL to GitLab Pages-built pages. Always belongs to a subdomain of `CI_PAGES_DOMAIN`. |
| `CI_PIPELINE_ID` | 8.10 | all | The unique id of the current pipeline that GitLab CI/CD uses internally |
| `CI_PIPELINE_IID` | 11.0 | all | The unique id of the current pipeline scoped to project |
-| `CI_PIPELINE_SOURCE` | 10.0 | all | Indicates how the pipeline was triggered. Possible options are: `push`, `web`, `trigger`, `schedule`, `api`, `pipeline`, `external`, `chat`, `merge_request_event`, and `external_pull_request_event`. For pipelines created before GitLab 9.5, this will show as `unknown` |
+| `CI_PIPELINE_SOURCE` | 10.0 | all | Indicates how the pipeline was triggered. Possible options are: `push`, `web`, `trigger`, `schedule`, `api`, `pipeline`, `parent_pipeline`, `external`, `chat`, `merge_request_event`, and `external_pull_request_event`. For pipelines created before GitLab 9.5, this will show as `unknown` |
| `CI_PIPELINE_TRIGGERED` | all | all | The flag to indicate that job was [triggered](../triggers/README.md) |
| `CI_PIPELINE_URL` | 11.1 | 0.5 | Pipeline details URL |
| `CI_PROJECT_DIR` | all | all | The full path where the repository is cloned and where the job is run. If the GitLab Runner `builds_dir` parameter is set, this variable is set relative to the value of `builds_dir`. For more information, see [Advanced configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) for GitLab Runner. |
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index efc9cad9810..c480db54705 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -468,7 +468,7 @@ helped us with overall code quality (using delegation, `&.` those
types of things), and making the code more robust.
**["Support multiple assignees for merge requests"](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/10161)**:
-A good example of collaboration on an MR touching multiple parts of the codebase. Nick pointed out interesting edge cases, James Lopes also joined in raising concerns on import/export feature.
+A good example of collaboration on an MR touching multiple parts of the codebase. Nick pointed out interesting edge cases, James Lopez also joined in raising concerns on import/export feature.
### Credits
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index 21e94a3464e..f016022576b 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -410,7 +410,7 @@ merge request with new or changed docs is submitted, are:
- If any code or the `doc/README.md` file is changed, a full pipeline will run, which
runs tests for [`/help`](#gitlab-help-tests).
-### Running tests & lint checks locally
+### Running tests
Apart from [previewing your changes locally](#previewing-the-changes-live), you can also run all lint checks
and Nanoc tests locally.
@@ -462,62 +462,20 @@ The output should be similar to:
Note that this requires you to either have the required lint tools installed on your machine,
or a working Docker installation, in which case an image with these tools pre-installed will be used.
-For more information on available linters refer to the [linting](#linting) section.
-
-### Linting
+### Local linting
To help adhere to the [documentation style guidelines](styleguide.md), and improve the content
added to documentation, consider locally installing and running documentation linters. This will
help you catch common issues before raising merge requests for review of documentation.
-The following are some suggested linters you can install locally and sample configuration:
+Running the following locally allows you to match the checks in the build pipeline:
-- [`proselint`](#proselint)
-- [markdownlint](#markdownlint), which is the same as the test run in [`docs-lint`](#testing)
-- [Vale](#vale), for English language grammar and syntax suggestions
+- [markdownlint](#markdownlint).
+- [Vale](#vale).
NOTE: **Note:**
This list does not limit what other linters you can add to your local documentation writing toolchain.
-#### `proselint`
-
-`proselint` checks for common problems with English prose. It provides a
- [plethora of checks](http://proselint.com/checks/) that are helpful for technical writing.
-
-`proselint` can be used [on the command line](http://proselint.com/utility/), either on a single
- Markdown file or on all Markdown files in a project. For example, to run `proselint` on all
- documentation in the [`gitlab` project](https://gitlab.com/gitlab-org/gitlab), run the
- following commands from within the `gitlab` project:
-
-```shell
-cd doc
-proselint **/*.md
-```
-
-`proselint` can also be run from within editors using plugins. For example, the following plugins
- are available:
-
-- [Sublime Text](https://packagecontrol.io/packages/SublimeLinter-contrib-proselint)
-- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=PatrykPeszko.vscode-proselint)
-- [Others](https://github.com/amperser/proselint#plugins-for-other-software)
-
-##### Sample `proselint` configuration
-
-All of the checks are good to use. However, excluding the `typography.symbols` and `misc.phrasal_adjectives` checks will reduce
-noise. The following sample `proselint` configuration disables these checks:
-
-```json
-{
- "checks": {
- "typography.symbols": false,
- "misc.phrasal_adjectives": false
- }
-}
-```
-
-A file with `proselint` configuration must be placed in a
-[valid location](https://github.com/amperser/proselint#checks). For example, `~/.config/proselint/config`.
-
#### markdownlint
[markdownlint](https://github.com/DavidAnson/markdownlint) checks that Markdown
@@ -596,8 +554,6 @@ You can also
[configure the text editor of your choice](https://errata-ai.github.io/vale/#local-use-by-a-single-writer)
to display the results.
-Vale's test results are not currently displayed in CI, but may be displayed in the future.
-
## Danger Bot
GitLab uses [Danger](https://github.com/danger/danger) for some elements in
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 8f58eb62fdd..75e38c3a5be 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -8,7 +8,7 @@ This document defines the standards for GitLab's documentation content and files
For broader information about the documentation, see the [Documentation guidelines](index.md).
-For programmatic help adhering to the guidelines, see [linting](index.md#linting).
+For programmatic help adhering to the guidelines, see [Testing](index.md#testing).
See the GitLab handbook for further [writing style guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines)
that apply to all GitLab content, not just documentation.
diff --git a/lib/gitlab/database/batch_count.rb b/lib/gitlab/database/batch_count.rb
index 5987dc34801..1faaac95575 100644
--- a/lib/gitlab/database/batch_count.rb
+++ b/lib/gitlab/database/batch_count.rb
@@ -19,8 +19,8 @@
module Gitlab
module Database
module BatchCount
- def batch_count(relation, column = nil, batch_size: nil)
- BatchCounter.new(relation, column: column).count(batch_size: batch_size)
+ def batch_count(relation, column = nil, batch_size: nil, start: nil, finish: nil)
+ BatchCounter.new(relation, column: column).count(batch_size: batch_size, start: start, finish: finish)
end
def batch_distinct_count(relation, column = nil, batch_size: nil, start: nil, finish: nil)
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index c5d2d8be022..7277d288d63 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -240,9 +240,9 @@ module Gitlab
{} # augmented in EE
end
- def count(relation, column = nil, fallback: -1, batch: true)
+ def count(relation, column = nil, fallback: -1, batch: true, start: nil, finish: nil)
if batch && Feature.enabled?(:usage_ping_batch_counter, default_enabled: true)
- Gitlab::Database::BatchCount.batch_count(relation, column)
+ Gitlab::Database::BatchCount.batch_count(relation, column, start: start, finish: finish)
else
relation.count
end
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
index 9cb9f9ba529..a07f0bd5e54 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Release' do
+ context 'Release', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/213222', type: :flaky } do
describe 'Deploy token creation' do
it 'user adds a deploy token' do
Flow::Login.sign_in
diff --git a/spec/features/projects/services/user_activates_asana_spec.rb b/spec/features/projects/services/user_activates_asana_spec.rb
index b07c77da554..dac60fce6e9 100644
--- a/spec/features/projects/services/user_activates_asana_spec.rb
+++ b/spec/features/projects/services/user_activates_asana_spec.rb
@@ -3,23 +3,14 @@
require 'spec_helper'
describe 'User activates Asana' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
- before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Asana')
- end
-
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Asana')
fill_in('Api key', with: 'verySecret')
fill_in('Restrict to branch', with: 'verySecret')
- click_button('Save')
+
+ click_test_then_save_integration
expect(page).to have_content('Asana activated.')
end
diff --git a/spec/features/projects/services/user_activates_assembla_spec.rb b/spec/features/projects/services/user_activates_assembla_spec.rb
index 56f7beb8f4b..999a95e3e23 100644
--- a/spec/features/projects/services/user_activates_assembla_spec.rb
+++ b/spec/features/projects/services/user_activates_assembla_spec.rb
@@ -3,22 +3,17 @@
require 'spec_helper'
describe 'User activates Assembla' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Assembla')
+ stub_request(:post, /.*atlas.assembla.com.*/)
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Assembla')
fill_in('Token', with: 'verySecret')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('Assembla activated.')
end
diff --git a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb b/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb
index c694eeb1cc2..28ed08f71b6 100644
--- a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb
+++ b/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb
@@ -3,31 +3,26 @@
require 'spec_helper'
describe 'User activates Atlassian Bamboo CI' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Atlassian Bamboo CI')
+ stub_request(:get, /.*bamboo.example.com.*/)
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Atlassian Bamboo CI')
fill_in('Bamboo url', with: 'http://bamboo.example.com')
fill_in('Build key', with: 'KEY')
fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('Atlassian Bamboo CI activated.')
# Password field should not be filled in.
click_link('Atlassian Bamboo CI')
- expect(find_field('Enter new password').value).to be_nil
+ expect(find_field('Enter new password').value).to be_blank
end
end
diff --git a/spec/features/projects/services/user_activates_emails_on_push_spec.rb b/spec/features/projects/services/user_activates_emails_on_push_spec.rb
index 2015b658295..42c069eb29e 100644
--- a/spec/features/projects/services/user_activates_emails_on_push_spec.rb
+++ b/spec/features/projects/services/user_activates_emails_on_push_spec.rb
@@ -3,22 +3,13 @@
require 'spec_helper'
describe 'User activates Emails on push' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
- before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Emails on push')
- end
-
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Emails on push')
fill_in('Recipients', with: 'qa@company.name')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('Emails on push activated.')
end
diff --git a/spec/features/projects/services/user_activates_flowdock_spec.rb b/spec/features/projects/services/user_activates_flowdock_spec.rb
index fc8e75daa0d..4762363b3fe 100644
--- a/spec/features/projects/services/user_activates_flowdock_spec.rb
+++ b/spec/features/projects/services/user_activates_flowdock_spec.rb
@@ -3,22 +3,19 @@
require 'spec_helper'
describe 'User activates Flowdock' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation' do
+ let(:project) { create(:project, :repository) }
+ end
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Flowdock')
+ stub_request(:post, /.*api.flowdock.com.*/)
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Flowdock')
fill_in('Token', with: 'verySecret')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('Flowdock activated.')
end
diff --git a/spec/features/projects/services/user_activates_hipchat_spec.rb b/spec/features/projects/services/user_activates_hipchat_spec.rb
index d6b69a5bd68..2fb056f3533 100644
--- a/spec/features/projects/services/user_activates_hipchat_spec.rb
+++ b/spec/features/projects/services/user_activates_hipchat_spec.rb
@@ -2,37 +2,37 @@
require 'spec_helper'
-describe 'User activates HipChat' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('HipChat')
- end
+describe 'User activates HipChat', :js do
+ include_context 'project service activation'
context 'with standart settings' do
+ before do
+ stub_request(:post, /.*api.hipchat.com.*/)
+ end
+
it 'activates service' do
- check('Active')
+ visit_project_integration('HipChat')
fill_in('Room', with: 'gitlab')
fill_in('Token', with: 'verySecret')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('HipChat activated.')
end
end
context 'with custom settings' do
+ before do
+ stub_request(:post, /.*chat.example.com.*/)
+ end
+
it 'activates service' do
- check('Active')
+ visit_project_integration('HipChat')
fill_in('Room', with: 'gitlab_custom')
fill_in('Token', with: 'secretCustom')
fill_in('Server', with: 'https://chat.example.com')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('HipChat activated.')
end
diff --git a/spec/features/projects/services/user_activates_irker_spec.rb b/spec/features/projects/services/user_activates_irker_spec.rb
index 898e16ce835..56df403499c 100644
--- a/spec/features/projects/services/user_activates_irker_spec.rb
+++ b/spec/features/projects/services/user_activates_irker_spec.rb
@@ -3,23 +3,14 @@
require 'spec_helper'
describe 'User activates Irker (IRC gateway)' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
- before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Irker (IRC gateway)')
- end
-
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Irker (IRC gateway)')
check('Colorize messages')
fill_in('Recipients', with: 'irc://chat.freenode.net/#commits')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('Irker (IRC gateway) activated.')
end
diff --git a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb
index 9842141285a..8c84a81ac89 100644
--- a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb
+++ b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb
@@ -3,27 +3,22 @@
require 'spec_helper'
describe 'User activates JetBrains TeamCity CI' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('JetBrains TeamCity CI')
+ stub_request(:post, /.*teamcity.example.com.*/)
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('JetBrains TeamCity CI')
check('Push')
check('Merge request')
fill_in('Teamcity url', with: 'http://teamcity.example.com')
fill_in('Build type', with: 'GitlabTest_Build')
fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('JetBrains TeamCity CI activated.')
end
diff --git a/spec/features/projects/services/user_activates_packagist_spec.rb b/spec/features/projects/services/user_activates_packagist_spec.rb
index 85bd15adbe5..274f293ebf3 100644
--- a/spec/features/projects/services/user_activates_packagist_spec.rb
+++ b/spec/features/projects/services/user_activates_packagist_spec.rb
@@ -3,23 +3,18 @@
require 'spec_helper'
describe 'User activates Packagist' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Packagist')
+ stub_request(:post, /.*packagist.org.*/)
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Packagist')
fill_in('Username', with: 'theUser')
fill_in('Token', with: 'verySecret')
- click_button('Save')
+
+ click_test_then_save_integration
expect(page).to have_content('Packagist activated.')
end
diff --git a/spec/features/projects/services/user_activates_pivotaltracker_spec.rb b/spec/features/projects/services/user_activates_pivotaltracker_spec.rb
index 67ff99c0295..c81c5081867 100644
--- a/spec/features/projects/services/user_activates_pivotaltracker_spec.rb
+++ b/spec/features/projects/services/user_activates_pivotaltracker_spec.rb
@@ -3,22 +3,17 @@
require 'spec_helper'
describe 'User activates PivotalTracker' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('PivotalTracker')
+ stub_request(:post, /.*www.pivotaltracker.com.*/)
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('PivotalTracker')
fill_in('Token', with: 'verySecret')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('PivotalTracker activated.')
end
diff --git a/spec/features/projects/services/user_activates_prometheus_spec.rb b/spec/features/projects/services/user_activates_prometheus_spec.rb
index ab372d532aa..76dc7d1bbc8 100644
--- a/spec/features/projects/services/user_activates_prometheus_spec.rb
+++ b/spec/features/projects/services/user_activates_prometheus_spec.rb
@@ -3,21 +3,17 @@
require 'spec_helper'
describe 'User activates Prometheus' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Prometheus')
+ stub_request(:get, /.*prometheus.example.com.*/)
end
- it 'does not activate service and informs about deprecation' do
+ it 'does not activate service and informs about deprecation', :js do
+ visit_project_integration('Prometheus')
check('Active')
fill_in('API URL', with: 'http://prometheus.example.com')
+
click_button('Save changes')
expect(page).not_to have_content('Prometheus activated.')
diff --git a/spec/features/projects/services/user_activates_pushover_spec.rb b/spec/features/projects/services/user_activates_pushover_spec.rb
index 34e1cf33f36..62e03e68aee 100644
--- a/spec/features/projects/services/user_activates_pushover_spec.rb
+++ b/spec/features/projects/services/user_activates_pushover_spec.rb
@@ -3,26 +3,21 @@
require 'spec_helper'
describe 'User activates Pushover' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ include_context 'project service activation'
before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
-
- click_link('Pushover')
+ stub_request(:post, /.*api.pushover.net.*/)
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
+ visit_project_integration('Pushover')
fill_in('Api key', with: 'verySecret')
fill_in('User key', with: 'verySecret')
fill_in('Device', with: 'myDevice')
select('High Priority', from: 'Priority')
select('Bike', from: 'Sound')
- click_button('Save')
+
+ click_test_integration
expect(page).to have_content('Pushover activated.')
end
diff --git a/spec/features/projects/services/user_activates_slack_notifications_spec.rb b/spec/features/projects/services/user_activates_slack_notifications_spec.rb
index f23b1d3102a..12f15699e26 100644
--- a/spec/features/projects/services/user_activates_slack_notifications_spec.rb
+++ b/spec/features/projects/services/user_activates_slack_notifications_spec.rb
@@ -3,32 +3,26 @@
require 'spec_helper'
describe 'User activates Slack notifications' do
- let(:user) { create(:user) }
- let(:service) { SlackService.new }
- let(:project) { create(:project, slack_service: service) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
+ include_context 'project service activation'
context 'when service is not configured yet' do
before do
- visit(project_settings_integrations_path(project))
-
- click_link('Slack notifications')
+ visit_project_integration('Slack notifications')
end
- it 'activates service' do
- check('Active')
+ it 'activates service', :js do
fill_in('Webhook', with: 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685')
- click_button('Save')
+
+ click_test_then_save_integration
expect(page).to have_content('Slack notifications activated.')
end
end
context 'when service is already configured' do
+ let(:service) { SlackService.new }
+ let(:project) { create(:project, slack_service: service) }
+
before do
service.fields
service.update(
diff --git a/spec/features/projects/services/user_views_services_spec.rb b/spec/features/projects/services/user_views_services_spec.rb
index cf403a131b0..6df0123c30a 100644
--- a/spec/features/projects/services/user_views_services_spec.rb
+++ b/spec/features/projects/services/user_views_services_spec.rb
@@ -3,17 +3,11 @@
require 'spec_helper'
describe 'User views services' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit(project_settings_integrations_path(project))
- end
+ include_context 'project service activation'
it 'shows the list of available services' do
+ visit_project_integrations
+
expect(page).to have_content('Integrations')
expect(page).to have_content('Campfire')
expect(page).to have_content('HipChat')
diff --git a/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js b/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
index 68f4c5c9e02..fb0964a3f32 100644
--- a/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
+++ b/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
@@ -1,7 +1,8 @@
import { shallowMount } from '@vue/test-utils';
import Popover from '~/blob/suggest_gitlab_ci_yml/components/popover.vue';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper';
import * as utils from '~/lib/utils/common_utils';
+import { GlDeprecatedButton } from '@gitlab/ui';
jest.mock('~/lib/utils/common_utils', () => ({
...jest.requireActual('~/lib/utils/common_utils'),
@@ -27,6 +28,9 @@ describe('Suggest gitlab-ci.yml Popover', () => {
dismissKey,
humanAccess,
},
+ stubs: {
+ 'gl-popover': '<div><slot name="title"></slot><slot></slot></div>',
+ },
});
}
@@ -88,6 +92,22 @@ describe('Suggest gitlab-ci.yml Popover', () => {
property: expectedProperty,
});
});
+
+ it('sends a tracking event when the popover is dismissed', () => {
+ const expectedLabel = commitTrackLabel;
+ const expectedAction = 'click_button';
+ const expectedProperty = 'owner';
+ const expectedValue = '10';
+ const dismissButton = wrapper.find(GlDeprecatedButton);
+
+ triggerEvent(dismissButton.element);
+
+ expect(trackingSpy).toHaveBeenCalledWith('_category_', expectedAction, {
+ label: expectedLabel,
+ property: expectedProperty,
+ value: expectedValue,
+ });
+ });
});
describe('when the popover is mounted with the trackLabel of the Confirm button popover at the bottom of the page', () => {
diff --git a/spec/frontend/fixtures/merge_requests.rb b/spec/frontend/fixtures/merge_requests.rb
index be11423ec41..a347ef683e7 100644
--- a/spec/frontend/fixtures/merge_requests.rb
+++ b/spec/frontend/fixtures/merge_requests.rb
@@ -94,7 +94,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
end
it 'merge_requests/discussions.json' do
- create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
+ create(:discussion_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
render_discussions_json(merge_request)
end
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 510876a5945..4e1bf2840dc 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -103,7 +103,7 @@ describe Gitlab::ClosingIssueExtractor do
end
it do
- message = "Awesome commit (Fixes: #{reference})"
+ message = "Awesome commit (fixes: #{reference})"
expect(subject.closed_by_message(message)).to eq([issue])
end
@@ -396,7 +396,7 @@ describe Gitlab::ClosingIssueExtractor do
end
it 'allows mixed comma-separated and non-comma-separated issue numbers in single line message' do
- message = "Closes #{reference}, #{reference2} and #{reference3}"
+ message = "Closes #{reference}, #{reference2} #{reference3}"
expect(subject.closed_by_message(message))
.to match_array([issue, other_issue, third_issue])
diff --git a/spec/lib/gitlab/database/batch_count_spec.rb b/spec/lib/gitlab/database/batch_count_spec.rb
index b126d8579fc..ec161cd6dcb 100644
--- a/spec/lib/gitlab/database/batch_count_spec.rb
+++ b/spec/lib/gitlab/database/batch_count_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
describe Gitlab::Database::BatchCount do
+ let_it_be(:fallback) { ::Gitlab::Database::BatchCounter::FALLBACK }
+ let_it_be(:small_batch_size) { ::Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE - 1 }
let(:model) { Issue }
let(:column) { :author_id }
@@ -37,9 +39,8 @@ describe Gitlab::Database::BatchCount do
expect(described_class.batch_count(model, batch_size: 50_000)).to eq(5)
end
- it 'will not count table with batch_size 1K' do
- fallback = ::Gitlab::Database::BatchCounter::FALLBACK
- expect(described_class.batch_count(model, batch_size: fallback / 2)).to eq(fallback)
+ it 'will not count table with a batch size less than allowed' do
+ expect(described_class.batch_count(model, batch_size: small_batch_size)).to eq(fallback)
end
it 'counts with a small edge case batch_sizes than result' do
@@ -57,6 +58,25 @@ describe Gitlab::Database::BatchCount do
end.to raise_error 'BatchCount can not be run inside a transaction'
end
end
+
+ it 'counts with a start and finish' do
+ expect(described_class.batch_count(model, start: model.minimum(:id), finish: model.maximum(:id))).to eq(5)
+ end
+
+ context 'disallowed configurations' do
+ it 'returns fallback if start is bigger than finish' do
+ expect(described_class.batch_count(model, start: 1, finish: 0)).to eq(fallback)
+ end
+
+ it 'returns fallback if loops more than allowed' do
+ large_finish = Gitlab::Database::BatchCounter::MAX_ALLOWED_LOOPS * Gitlab::Database::BatchCounter::DEFAULT_BATCH_SIZE + 1
+ expect(described_class.batch_count(model, start: 1, finish: large_finish)).to eq(fallback)
+ end
+
+ it 'returns fallback if batch size is less than min required' do
+ expect(described_class.batch_count(model, batch_size: small_batch_size)).to eq(fallback)
+ end
+ end
end
describe '#batch_distinct_count' do
@@ -80,9 +100,8 @@ describe Gitlab::Database::BatchCount do
expect(described_class.batch_distinct_count(model, column, batch_size: 50_000)).to eq(2)
end
- it 'will not count table with batch_size 1K' do
- fallback = ::Gitlab::Database::BatchCounter::FALLBACK
- expect(described_class.batch_distinct_count(model, column, batch_size: fallback / 2)).to eq(fallback)
+ it 'will not count table with a batch size less than allowed' do
+ expect(described_class.batch_distinct_count(model, column, batch_size: small_batch_size)).to eq(fallback)
end
it 'counts with a small edge case batch_sizes than result' do
@@ -98,5 +117,20 @@ describe Gitlab::Database::BatchCount do
it 'counts with User min and max as start and finish' do
expect(described_class.batch_distinct_count(model, column, start: User.minimum(:id), finish: User.maximum(:id))).to eq(2)
end
+
+ context 'disallowed configurations' do
+ it 'returns fallback if start is bigger than finish' do
+ expect(described_class.batch_distinct_count(model, column, start: 1, finish: 0)).to eq(fallback)
+ end
+
+ it 'returns fallback if loops more than allowed' do
+ large_finish = Gitlab::Database::BatchCounter::MAX_ALLOWED_LOOPS * Gitlab::Database::BatchCounter::DEFAULT_DISTINCT_BATCH_SIZE + 1
+ expect(described_class.batch_distinct_count(model, column, start: 1, finish: large_finish)).to eq(fallback)
+ end
+
+ it 'returns fallback if batch size is less than min required' do
+ expect(described_class.batch_distinct_count(model, column, batch_size: small_batch_size)).to eq(fallback)
+ end
+ end
end
end
diff --git a/spec/services/projects/prometheus/metrics/destroy_service_spec.rb b/spec/services/projects/prometheus/metrics/destroy_service_spec.rb
new file mode 100644
index 00000000000..81fce82cf46
--- /dev/null
+++ b/spec/services/projects/prometheus/metrics/destroy_service_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Prometheus::Metrics::DestroyService do
+ let(:metric) { create(:prometheus_metric) }
+
+ subject { described_class.new(metric) }
+
+ it 'destroys metric' do
+ subject.execute
+
+ expect(PrometheusMetric.find_by(id: metric.id)).to be_nil
+ end
+
+ context 'when metric has a prometheus alert associated' do
+ it 'schedules a prometheus alert update' do
+ create(:prometheus_alert, project: metric.project, prometheus_metric: metric)
+
+ schedule_update_service = spy
+ allow(::Clusters::Applications::ScheduleUpdateService).to receive(:new).and_return(schedule_update_service)
+
+ subject.execute
+
+ expect(schedule_update_service).to have_received(:execute)
+ end
+ end
+end
diff --git a/spec/services/projects/prometheus/metrics/update_service_spec.rb b/spec/services/projects/prometheus/metrics/update_service_spec.rb
new file mode 100644
index 00000000000..a53c6ae37cd
--- /dev/null
+++ b/spec/services/projects/prometheus/metrics/update_service_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Prometheus::Metrics::UpdateService do
+ let(:metric) { create(:prometheus_metric) }
+
+ it 'updates the prometheus metric' do
+ expect do
+ described_class.new(metric, { title: "bar" }).execute
+ end.to change { metric.reload.title }.to("bar")
+ end
+
+ context 'when metric has a prometheus alert associated' do
+ let(:schedule_update_service) { spy }
+
+ before do
+ create(:prometheus_alert, project: metric.project, prometheus_metric: metric)
+ allow(::Clusters::Applications::ScheduleUpdateService).to receive(:new).and_return(schedule_update_service)
+ end
+
+ context 'when updating title' do
+ it 'schedules a prometheus alert update' do
+ described_class.new(metric, { title: "bar" }).execute
+
+ expect(schedule_update_service).to have_received(:execute)
+ end
+ end
+
+ context 'when updating query' do
+ it 'schedules a prometheus alert update' do
+ described_class.new(metric, { query: "sum(bar)" }).execute
+
+ expect(schedule_update_service).to have_received(:execute)
+ end
+ end
+
+ it 'does not schedule a prometheus alert update without title nor query being changed' do
+ described_class.new(metric, { y_label: "bar" }).execute
+
+ expect(schedule_update_service).not_to have_received(:execute)
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/project_service_shared_context.rb b/spec/support/shared_contexts/project_service_shared_context.rb
new file mode 100644
index 00000000000..89b196e7039
--- /dev/null
+++ b/spec/support/shared_contexts/project_service_shared_context.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+shared_context 'project service activation' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ def visit_project_integrations
+ visit project_settings_integrations_path(project)
+ end
+
+ def visit_project_integration(name)
+ visit_project_integrations
+ click_link(name)
+ end
+
+ def click_test_integration
+ click_button('Test settings and save changes')
+ end
+
+ def click_test_then_save_integration
+ click_test_integration
+
+ expect(page).to have_content('Test failed.')
+
+ click_link('Save anyway')
+ end
+end