diff options
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 |