summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintignore1
-rw-r--r--.gitlab-ci.yml14
-rw-r--r--.rubocop.yml14
-rw-r--r--.scss-lint.yml4
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/images/select2-spinner.gifbin0 -> 1849 bytes
-rw-r--r--app/assets/images/select2.pngbin0 -> 613 bytes
-rw-r--r--app/assets/images/select2x2.pngbin0 -> 845 bytes
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue30
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue30
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue29
-rw-r--r--app/assets/javascripts/error_tracking/store/actions.js2
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js25
-rw-r--r--app/assets/javascripts/monitoring/components/charts/area.vue10
-rw-r--r--app/assets/javascripts/monitoring/constants.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/svg_gradient.vue6
-rw-r--r--app/assets/stylesheets/components/related_items_list.scss1
-rw-r--r--app/assets/stylesheets/framework/common.scss8
-rw-r--r--app/assets/stylesheets/framework/forms.scss2
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss4
-rw-r--r--app/assets/stylesheets/framework/page_title.scss1
-rw-r--r--app/controllers/clusters/clusters_controller.rb10
-rw-r--r--app/controllers/projects/blob_controller.rb3
-rw-r--r--app/controllers/projects/merge_requests_controller.rb4
-rw-r--r--app/controllers/search_controller.rb2
-rw-r--r--app/finders/groups_finder.rb8
-rw-r--r--app/helpers/groups_helper.rb5
-rw-r--r--app/helpers/search_helper.rb4
-rw-r--r--app/models/abuse_report.rb2
-rw-r--r--app/models/appearance.rb2
-rw-r--r--app/models/application_record.rb8
-rw-r--r--app/models/application_setting.rb2
-rw-r--r--app/models/application_setting/term.rb2
-rw-r--r--app/models/audit_event.rb2
-rw-r--r--app/models/award_emoji.rb2
-rw-r--r--app/models/badge.rb2
-rw-r--r--app/models/board.rb2
-rw-r--r--app/models/board_group_recent_visit.rb2
-rw-r--r--app/models/board_project_recent_visit.rb2
-rw-r--r--app/models/broadcast_message.rb2
-rw-r--r--app/models/chat_name.rb2
-rw-r--r--app/models/chat_team.rb2
-rw-r--r--app/models/ci/build.rb6
-rw-r--r--app/models/ci/build_metadata.rb2
-rw-r--r--app/models/ci/build_runner_session.rb2
-rw-r--r--app/models/ci/build_trace_chunk.rb2
-rw-r--r--app/models/ci/build_trace_section.rb2
-rw-r--r--app/models/ci/build_trace_section_name.rb2
-rw-r--r--app/models/ci/group_variable.rb2
-rw-r--r--app/models/ci/job_artifact.rb2
-rw-r--r--app/models/ci/pipeline.rb38
-rw-r--r--app/models/ci/pipeline_chat_data.rb2
-rw-r--r--app/models/ci/pipeline_schedule.rb2
-rw-r--r--app/models/ci/pipeline_schedule_variable.rb2
-rw-r--r--app/models/ci/pipeline_variable.rb2
-rw-r--r--app/models/ci/runner.rb2
-rw-r--r--app/models/ci/runner_namespace.rb2
-rw-r--r--app/models/ci/runner_project.rb2
-rw-r--r--app/models/ci/stage.rb2
-rw-r--r--app/models/ci/trigger.rb2
-rw-r--r--app/models/ci/trigger_request.rb2
-rw-r--r--app/models/ci/variable.rb2
-rw-r--r--app/models/clusters/applications/cert_manager.rb2
-rw-r--r--app/models/clusters/applications/helm.rb2
-rw-r--r--app/models/clusters/applications/ingress.rb2
-rw-r--r--app/models/clusters/applications/jupyter.rb2
-rw-r--r--app/models/clusters/applications/knative.rb2
-rw-r--r--app/models/clusters/applications/prometheus.rb2
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/clusters/cluster.rb19
-rw-r--r--app/models/clusters/group.rb2
-rw-r--r--app/models/clusters/kubernetes_namespace.rb2
-rw-r--r--app/models/clusters/platforms/kubernetes.rb6
-rw-r--r--app/models/clusters/project.rb2
-rw-r--r--app/models/clusters/providers/gcp.rb2
-rw-r--r--app/models/commit_status.rb2
-rw-r--r--app/models/concerns/atomic_internal_id.rb2
-rw-r--r--app/models/concerns/ignorable_column.rb2
-rw-r--r--app/models/concerns/participable.rb2
-rw-r--r--app/models/concerns/reactive_caching.rb2
-rw-r--r--app/models/concerns/sha_attribute.rb2
-rw-r--r--app/models/concerns/strip_attribute.rb2
-rw-r--r--app/models/container_repository.rb2
-rw-r--r--app/models/conversational_development_index/metric.rb2
-rw-r--r--app/models/deploy_keys_project.rb2
-rw-r--r--app/models/deploy_token.rb2
-rw-r--r--app/models/deployment.rb2
-rw-r--r--app/models/email.rb2
-rw-r--r--app/models/environment.rb2
-rw-r--r--app/models/epic.rb2
-rw-r--r--app/models/error_tracking/project_error_tracking_setting.rb9
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/fork_network.rb2
-rw-r--r--app/models/fork_network_member.rb2
-rw-r--r--app/models/gpg_key.rb2
-rw-r--r--app/models/gpg_key_subkey.rb2
-rw-r--r--app/models/group_custom_attribute.rb2
-rw-r--r--app/models/hooks/web_hook.rb2
-rw-r--r--app/models/hooks/web_hook_log.rb2
-rw-r--r--app/models/identity.rb2
-rw-r--r--app/models/identity/uniqueness_scopes.rb2
-rw-r--r--app/models/import_export_upload.rb2
-rw-r--r--app/models/internal_id.rb2
-rw-r--r--app/models/issue.rb2
-rw-r--r--app/models/issue/metrics.rb2
-rw-r--r--app/models/issue_assignee.rb2
-rw-r--r--app/models/key.rb2
-rw-r--r--app/models/label.rb2
-rw-r--r--app/models/label_link.rb2
-rw-r--r--app/models/label_priority.rb2
-rw-r--r--app/models/lfs_file_lock.rb2
-rw-r--r--app/models/lfs_object.rb2
-rw-r--r--app/models/lfs_objects_project.rb2
-rw-r--r--app/models/list.rb2
-rw-r--r--app/models/member.rb2
-rw-r--r--app/models/merge_request.rb11
-rw-r--r--app/models/merge_request/metrics.rb2
-rw-r--r--app/models/merge_request_diff.rb2
-rw-r--r--app/models/merge_request_diff_commit.rb2
-rw-r--r--app/models/merge_request_diff_file.rb2
-rw-r--r--app/models/merge_requests_closing_issues.rb2
-rw-r--r--app/models/milestone.rb2
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/note_diff_file.rb2
-rw-r--r--app/models/notification_setting.rb2
-rw-r--r--app/models/pages_domain.rb2
-rw-r--r--app/models/personal_access_token.rb2
-rw-r--r--app/models/pool_repository.rb2
-rw-r--r--app/models/postgresql/replication_slot.rb2
-rw-r--r--app/models/programming_language.rb2
-rw-r--r--app/models/project.rb2
-rw-r--r--app/models/project_authorization.rb2
-rw-r--r--app/models/project_auto_devops.rb2
-rw-r--r--app/models/project_ci_cd_setting.rb2
-rw-r--r--app/models/project_custom_attribute.rb2
-rw-r--r--app/models/project_daily_statistic.rb2
-rw-r--r--app/models/project_deploy_token.rb2
-rw-r--r--app/models/project_feature.rb2
-rw-r--r--app/models/project_group_link.rb2
-rw-r--r--app/models/project_import_data.rb2
-rw-r--r--app/models/project_import_state.rb2
-rw-r--r--app/models/project_repository.rb2
-rw-r--r--app/models/project_statistics.rb2
-rw-r--r--app/models/prometheus_metric.rb2
-rw-r--r--app/models/protected_branch.rb2
-rw-r--r--app/models/protected_branch/merge_access_level.rb2
-rw-r--r--app/models/protected_branch/push_access_level.rb2
-rw-r--r--app/models/protected_tag.rb2
-rw-r--r--app/models/protected_tag/create_access_level.rb2
-rw-r--r--app/models/push_event_payload.rb2
-rw-r--r--app/models/redirect_route.rb2
-rw-r--r--app/models/release.rb2
-rw-r--r--app/models/releases/link.rb2
-rw-r--r--app/models/remote_mirror.rb2
-rw-r--r--app/models/repository_language.rb2
-rw-r--r--app/models/resource_label_event.rb2
-rw-r--r--app/models/route.rb2
-rw-r--r--app/models/sent_notification.rb2
-rw-r--r--app/models/service.rb2
-rw-r--r--app/models/shard.rb2
-rw-r--r--app/models/snippet.rb2
-rw-r--r--app/models/spam_log.rb2
-rw-r--r--app/models/subscription.rb2
-rw-r--r--app/models/system_note_metadata.rb2
-rw-r--r--app/models/term_agreement.rb2
-rw-r--r--app/models/timelog.rb2
-rw-r--r--app/models/todo.rb2
-rw-r--r--app/models/trending_project.rb2
-rw-r--r--app/models/u2f_registration.rb2
-rw-r--r--app/models/upload.rb2
-rw-r--r--app/models/user.rb2
-rw-r--r--app/models/user_agent_detail.rb2
-rw-r--r--app/models/user_callout.rb2
-rw-r--r--app/models/user_custom_attribute.rb2
-rw-r--r--app/models/user_interacted_project.rb2
-rw-r--r--app/models/user_preference.rb2
-rw-r--r--app/models/user_status.rb2
-rw-r--r--app/models/user_synced_attributes_metadata.rb2
-rw-r--r--app/models/users_star_project.rb2
-rw-r--r--app/presenters/ci/build_runner_presenter.rb9
-rw-r--r--app/presenters/clusters/cluster_presenter.rb4
-rw-r--r--app/services/clusters/applications/base_service.rb24
-rw-r--r--app/services/clusters/applications/create_service.rb22
-rw-r--r--app/services/clusters/applications/update_service.rb21
-rw-r--r--app/services/error_tracking/list_issues_service.rb11
-rw-r--r--app/services/issuable_base_service.rb6
-rw-r--r--app/services/merge_requests/base_service.rb26
-rw-r--r--app/services/merge_requests/create_service.rb2
-rw-r--r--app/services/merge_requests/delete_non_latest_diffs_service.rb4
-rw-r--r--app/services/merge_requests/merge_to_ref_service.rb4
-rw-r--r--app/services/merge_requests/refresh_service.rb2
-rw-r--r--app/services/milestones/promote_service.rb4
-rw-r--r--app/services/projects/after_import_service.rb2
-rw-r--r--app/services/projects/housekeeping_service.rb5
-rw-r--r--app/services/quick_actions/interpret_service.rb619
-rw-r--r--app/uploaders/object_storage.rb6
-rw-r--r--app/validators/cluster_name_validator.rb8
-rw-r--r--app/views/admin/runners/_runner.html.haml2
-rw-r--r--app/views/clusters/clusters/_advanced_settings.html.haml2
-rw-r--r--app/views/clusters/clusters/show.html.haml2
-rw-r--r--app/views/clusters/platforms/kubernetes/_form.html.haml14
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml4
-rw-r--r--app/views/notify/_note_email.text.erb4
-rw-r--r--app/views/projects/_md_preview.html.haml2
-rw-r--r--changelogs/unreleased/10735-geo-gitlab-revision-can-return-not-consistent-results.yml5
-rw-r--r--changelogs/unreleased/24936-remove-type-from-review-app-name.yml5
-rw-r--r--changelogs/unreleased/53210-add-uniq-constraints-on-issues-and-mrs-labels.yml5
-rw-r--r--changelogs/unreleased/57669-fix-bug-clicking-file-header-refreshes-page.yml6
-rw-r--r--changelogs/unreleased/58793-fix-nav-links-archived-project.yml5
-rw-r--r--changelogs/unreleased/58971-sentry-api-keyerror.yml5
-rw-r--r--changelogs/unreleased/59441-add-base-domain-to-cluster-api.yml5
-rw-r--r--changelogs/unreleased/check-mergeability-in-merge-to-ref-service.yml5
-rw-r--r--changelogs/unreleased/fix-container-scanning-on-k8s.yml5
-rw-r--r--changelogs/unreleased/fix-transfer-group-possibilities.yml5
-rw-r--r--changelogs/unreleased/nfriend-css-updates-for-gitlab-design-system-compliance.yml5
-rw-r--r--changelogs/unreleased/persist-fulll-ref-path-for-mr-pipelines.yml5
-rw-r--r--changelogs/unreleased/related-mr-link-cutoff.yml5
-rw-r--r--changelogs/unreleased/sh-fix-gitaly-find-commit-caching.yml5
-rw-r--r--changelogs/unreleased/sh-fix-project-branches-merge-status.yml5
-rw-r--r--changelogs/unreleased/sh-force-gc-after-import.yml5
-rw-r--r--config/helpers/is_ee_env.js9
-rw-r--r--config/initializers/jira.rb11
-rw-r--r--config/webpack.config.js6
-rw-r--r--db/migrate/20190325165127_add_managed_to_cluster.rb17
-rw-r--r--db/schema.rb3
-rw-r--r--doc/administration/pages/index.md29
-rw-r--r--doc/api/commits.md30
-rw-r--r--doc/api/project_clusters.md7
-rw-r--r--doc/api/services.md2
-rw-r--r--doc/ci/README.md45
-rw-r--r--doc/ci/environments.md681
-rw-r--r--doc/ci/environments/protected_environments.md48
-rw-r--r--doc/ci/introduction/img/gitlab_workflow_example.pngbin55394 -> 0 bytes
-rw-r--r--doc/ci/introduction/img/gitlab_workflow_example_11_9.pngbin0 -> 71292 bytes
-rw-r--r--doc/ci/introduction/index.md2
-rw-r--r--doc/ci/quick_start/README.md2
-rw-r--r--doc/ci/variables/README.md35
-rw-r--r--doc/ci/variables/deprecated_variables.md27
-rw-r--r--doc/ci/yaml/README.md25
-rw-r--r--doc/development/contributing/index.md7
-rw-r--r--doc/development/ee_features.md13
-rw-r--r--doc/development/i18n/proofreader.md3
-rw-r--r--doc/development/sql.md15
-rw-r--r--doc/topics/autodevops/index.md50
-rw-r--r--doc/user/profile/personal_access_tokens.md7
-rw-r--r--doc/user/project/pipelines/schedules.md121
-rw-r--r--doc/workflow/lfs/lfs_administration.md12
-rw-r--r--jest.config.js5
-rw-r--r--lib/api/branches.rb4
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/api/project_clusters.rb2
-rw-r--r--lib/gitlab.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb7
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/abilities.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/repository.rb2
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml9
-rw-r--r--lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml15
-rw-r--r--lib/gitlab/current_settings.rb2
-rw-r--r--lib/gitlab/encoding_helper.rb7
-rw-r--r--lib/gitlab/gitaly_client.rb22
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb2
-rw-r--r--lib/gitlab/gitaly_client/conflicts_service.rb2
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb4
-rw-r--r--lib/gitlab/gitaly_client/wiki_service.rb4
-rw-r--r--lib/gitlab/quick_actions/command_definition.rb8
-rw-r--r--lib/gitlab/quick_actions/commit_actions.rb31
-rw-r--r--lib/gitlab/quick_actions/common_actions.rb17
-rw-r--r--lib/gitlab/quick_actions/dsl.rb23
-rw-r--r--lib/gitlab/quick_actions/issuable_actions.rb221
-rw-r--r--lib/gitlab/quick_actions/issue_actions.rb136
-rw-r--r--lib/gitlab/quick_actions/issue_and_merge_request_actions.rb225
-rw-r--r--lib/gitlab/quick_actions/merge_request_actions.rb59
-rw-r--r--lib/sentry/client.rb32
-rw-r--r--lib/tasks/gitlab/db.rake5
-rw-r--r--lib/tasks/tokens.rake2
-rw-r--r--package.json3
-rw-r--r--qa/qa/page/dashboard/groups.rb6
-rw-r--r--qa/qa/page/dashboard/snippet/new.rb2
-rw-r--r--qa/qa/page/group/show.rb2
-rw-r--r--qa/qa/page/label/index.rb2
-rw-r--r--qa/qa/page/label/new.rb2
-rw-r--r--qa/qa/page/main/menu.rb6
-rw-r--r--qa/qa/page/merge_request/show.rb4
-rw-r--r--qa/qa/page/profile/personal_access_tokens.rb2
-rw-r--r--qa/qa/page/project/issue/index.rb2
-rw-r--r--qa/qa/page/project/milestone/new.rb2
-rw-r--r--qa/qa/page/project/new.rb6
-rw-r--r--qa/qa/page/project/operations/environments/index.rb2
-rw-r--r--qa/qa/page/project/pipeline/index.rb2
-rw-r--r--qa/qa/page/project/pipeline/show.rb4
-rw-r--r--qa/qa/page/project/settings/protected_branches.rb10
-rw-r--r--qa/qa/page/project/show.rb4
-rw-r--r--qa/qa/page/project/sub_menus/operations.rb4
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb2
-rw-r--r--qa/qa/page/project/sub_menus/settings.rb8
-rw-r--r--qa/qa/page/project/wiki/edit.rb10
-rw-r--r--qa/qa/page/project/wiki/new.rb2
-rw-r--r--qa/qa/page/project/wiki/show.rb2
-rw-r--r--qa/qa/resource/branch.rb2
-rw-r--r--qa/qa/resource/ci_variable.rb2
-rw-r--r--qa/qa/resource/deploy_key.rb2
-rw-r--r--qa/qa/resource/deploy_token.rb2
-rw-r--r--qa/qa/resource/group.rb2
-rw-r--r--qa/qa/resource/kubernetes_cluster.rb2
-rw-r--r--qa/qa/resource/label.rb4
-rw-r--r--qa/qa/resource/personal_access_token.rb4
-rw-r--r--qa/qa/resource/project_imported_from_github.rb4
-rw-r--r--qa/qa/resource/project_milestone.rb2
-rw-r--r--qa/qa/resource/repository/wiki_push.rb2
-rw-r--r--qa/qa/resource/runner.rb2
-rw-r--r--qa/qa/resource/sandbox.rb4
-rw-r--r--qa/qa/resource/settings/hashed_storage.rb2
-rw-r--r--qa/qa/resource/snippet.rb2
-rw-r--r--qa/qa/resource/ssh_key.rb2
-rw-r--r--qa/qa/resource/wiki.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb2
-rw-r--r--qa/qa/tools/revoke_all_personal_access_tokens.rb2
-rwxr-xr-xscripts/insert-rspec-profiling-data2
-rwxr-xr-xscripts/review_apps/review-apps.sh286
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb4
-rw-r--r--spec/factories/clusters/clusters.rb5
-rw-r--r--spec/factories/merge_requests.rb17
-rw-r--r--spec/features/clusters/cluster_detail_page_spec.rb80
-rw-r--r--spec/features/issues/user_uses_quick_actions_spec.rb97
-rw-r--r--spec/features/merge_request/user_uses_quick_actions_spec.rb57
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb38
-rw-r--r--spec/features/users/login_spec.rb2
-rw-r--r--spec/frontend/.eslintrc.yml9
-rw-r--r--spec/frontend/environment.js25
-rw-r--r--spec/frontend/helpers/class_spec_helper.js9
-rw-r--r--spec/frontend/helpers/fixtures.js26
-rw-r--r--spec/frontend/helpers/locale_helper.js11
-rw-r--r--spec/frontend/helpers/scroll_into_view_promise.js28
-rw-r--r--spec/frontend/helpers/set_timeout_promise_helper.js4
-rw-r--r--spec/frontend/helpers/user_mock_data_helper.js14
-rw-r--r--spec/frontend/helpers/vue_component_helper.js18
-rw-r--r--spec/frontend/helpers/vue_resource_helper.js11
-rw-r--r--spec/frontend/helpers/vue_test_utils_helper.js19
-rw-r--r--spec/frontend/helpers/vuex_action_helper.js104
-rw-r--r--spec/frontend/helpers/wait_for_attribute_change.js16
-rw-r--r--spec/frontend/helpers/wait_for_promises.js1
-rw-r--r--spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js (renamed from spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js)4
-rw-r--r--spec/frontend/reports/components/report_section_spec.js (renamed from spec/javascripts/reports/components/report_section_spec.js)2
-rw-r--r--spec/frontend/test_setup.js42
-rw-r--r--spec/graphql/types/permission_types/issue_spec.rb4
-rw-r--r--spec/graphql/types/permission_types/project_spec.rb4
-rw-r--r--spec/helpers/appearances_helper_spec.rb8
-rw-r--r--spec/helpers/auth_helper_spec.rb2
-rw-r--r--spec/helpers/groups_helper_spec.rb35
-rw-r--r--spec/helpers/issuables_helper_spec.rb6
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb2
-rw-r--r--spec/helpers/projects_helper_spec.rb2
-rw-r--r--spec/javascripts/diffs/components/diff_file_header_spec.js71
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js33
-rw-r--r--spec/javascripts/monitoring/charts/area_spec.js4
-rw-r--r--spec/javascripts/monitoring/mock_data.js5
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/command_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb47
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb19
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb15
-rw-r--r--spec/lib/gitlab/encoding_helper_spec.rb13
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb15
-rw-r--r--spec/lib/gitlab/quick_actions/command_definition_spec.rb30
-rw-r--r--spec/lib/gitlab/quick_actions/dsl_spec.rb26
-rw-r--r--spec/lib/gitlab_spec.rb2
-rw-r--r--spec/lib/sentry/client_spec.rb85
-rw-r--r--spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb26
-rw-r--r--spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb24
-rw-r--r--spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb12
-rw-r--r--spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb20
-rw-r--r--spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb12
-rw-r--r--spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb22
-rw-r--r--spec/models/ability_spec.rb2
-rw-r--r--spec/models/abuse_report_spec.rb2
-rw-r--r--spec/models/active_session_spec.rb2
-rw-r--r--spec/models/appearance_spec.rb2
-rw-r--r--spec/models/application_setting/term_spec.rb2
-rw-r--r--spec/models/application_setting_spec.rb2
-rw-r--r--spec/models/award_emoji_spec.rb2
-rw-r--r--spec/models/badge_spec.rb2
-rw-r--r--spec/models/badges/group_badge_spec.rb2
-rw-r--r--spec/models/badges/project_badge_spec.rb2
-rw-r--r--spec/models/blob_spec.rb2
-rw-r--r--spec/models/blob_viewer/base_spec.rb2
-rw-r--r--spec/models/blob_viewer/changelog_spec.rb2
-rw-r--r--spec/models/blob_viewer/composer_json_spec.rb2
-rw-r--r--spec/models/blob_viewer/gemspec_spec.rb2
-rw-r--r--spec/models/blob_viewer/gitlab_ci_yml_spec.rb2
-rw-r--r--spec/models/blob_viewer/license_spec.rb2
-rw-r--r--spec/models/blob_viewer/package_json_spec.rb2
-rw-r--r--spec/models/blob_viewer/podspec_json_spec.rb2
-rw-r--r--spec/models/blob_viewer/podspec_spec.rb2
-rw-r--r--spec/models/blob_viewer/readme_spec.rb2
-rw-r--r--spec/models/blob_viewer/route_map_spec.rb2
-rw-r--r--spec/models/blob_viewer/server_side_spec.rb2
-rw-r--r--spec/models/board_spec.rb2
-rw-r--r--spec/models/broadcast_message_spec.rb2
-rw-r--r--spec/models/chat_name_spec.rb2
-rw-r--r--spec/models/chat_team_spec.rb2
-rw-r--r--spec/models/ci/artifact_blob_spec.rb2
-rw-r--r--spec/models/ci/bridge_spec.rb2
-rw-r--r--spec/models/ci/build_metadata_spec.rb2
-rw-r--r--spec/models/ci/build_runner_session_spec.rb2
-rw-r--r--spec/models/ci/build_spec.rb22
-rw-r--r--spec/models/ci/build_trace_chunks/database_spec.rb2
-rw-r--r--spec/models/ci/build_trace_chunks/fog_spec.rb2
-rw-r--r--spec/models/ci/build_trace_chunks/redis_spec.rb2
-rw-r--r--spec/models/ci/build_trace_section_name_spec.rb2
-rw-r--r--spec/models/ci/build_trace_section_spec.rb2
-rw-r--r--spec/models/ci/group_spec.rb2
-rw-r--r--spec/models/ci/group_variable_spec.rb2
-rw-r--r--spec/models/ci/job_artifact_spec.rb2
-rw-r--r--spec/models/ci/legacy_stage_spec.rb2
-rw-r--r--spec/models/ci/pipeline_schedule_spec.rb2
-rw-r--r--spec/models/ci/pipeline_schedule_variable_spec.rb2
-rw-r--r--spec/models/ci/pipeline_spec.rb46
-rw-r--r--spec/models/ci/pipeline_variable_spec.rb2
-rw-r--r--spec/models/ci/runner_spec.rb2
-rw-r--r--spec/models/ci/stage_spec.rb2
-rw-r--r--spec/models/ci/trigger_request_spec.rb2
-rw-r--r--spec/models/ci/trigger_spec.rb2
-rw-r--r--spec/models/ci/variable_spec.rb2
-rw-r--r--spec/models/clusters/applications/cert_manager_spec.rb29
-rw-r--r--spec/models/clusters/applications/helm_spec.rb2
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb2
-rw-r--r--spec/models/clusters/applications/jupyter_spec.rb2
-rw-r--r--spec/models/clusters/applications/knative_spec.rb2
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb2
-rw-r--r--spec/models/clusters/applications/runner_spec.rb2
-rw-r--r--spec/models/clusters/cluster_spec.rb16
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb4
-rw-r--r--spec/models/clusters/project_spec.rb2
-rw-r--r--spec/models/clusters/providers/gcp_spec.rb2
-rw-r--r--spec/models/commit_collection_spec.rb2
-rw-r--r--spec/models/commit_range_spec.rb2
-rw-r--r--spec/models/commit_spec.rb2
-rw-r--r--spec/models/commit_status_spec.rb2
-rw-r--r--spec/models/compare_spec.rb2
-rw-r--r--spec/models/concerns/access_requestable_spec.rb2
-rw-r--r--spec/models/concerns/avatarable_spec.rb2
-rw-r--r--spec/models/concerns/awardable_spec.rb2
-rw-r--r--spec/models/concerns/batch_destroy_dependent_associations_spec.rb2
-rw-r--r--spec/models/concerns/blocks_json_serialization_spec.rb2
-rw-r--r--spec/models/concerns/cache_markdown_field_spec.rb2
-rw-r--r--spec/models/concerns/cacheable_attributes_spec.rb2
-rw-r--r--spec/models/concerns/case_sensitivity_spec.rb2
-rw-r--r--spec/models/concerns/chronic_duration_attribute_spec.rb2
-rw-r--r--spec/models/concerns/deployable_spec.rb2
-rw-r--r--spec/models/concerns/deployment_platform_spec.rb2
-rw-r--r--spec/models/concerns/discussion_on_diff_spec.rb2
-rw-r--r--spec/models/concerns/each_batch_spec.rb2
-rw-r--r--spec/models/concerns/editable_spec.rb2
-rw-r--r--spec/models/concerns/expirable_spec.rb2
-rw-r--r--spec/models/concerns/faster_cache_keys_spec.rb2
-rw-r--r--spec/models/concerns/feature_gate_spec.rb2
-rw-r--r--spec/models/concerns/group_descendant_spec.rb2
-rw-r--r--spec/models/concerns/has_status_spec.rb2
-rw-r--r--spec/models/concerns/has_variable_spec.rb2
-rw-r--r--spec/models/concerns/ignorable_column_spec.rb2
-rw-r--r--spec/models/concerns/issuable_spec.rb2
-rw-r--r--spec/models/concerns/loaded_in_group_list_spec.rb2
-rw-r--r--spec/models/concerns/manual_inverse_association_spec.rb2
-rw-r--r--spec/models/concerns/mentionable_spec.rb2
-rw-r--r--spec/models/concerns/milestoneish_spec.rb2
-rw-r--r--spec/models/concerns/noteable_spec.rb2
-rw-r--r--spec/models/concerns/participable_spec.rb2
-rw-r--r--spec/models/concerns/presentable_spec.rb2
-rw-r--r--spec/models/concerns/project_features_compatibility_spec.rb2
-rw-r--r--spec/models/concerns/prometheus_adapter_spec.rb2
-rw-r--r--spec/models/concerns/protected_ref_access_spec.rb2
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb2
-rw-r--r--spec/models/concerns/redactable_spec.rb2
-rw-r--r--spec/models/concerns/redis_cacheable_spec.rb2
-rw-r--r--spec/models/concerns/relative_positioning_spec.rb2
-rw-r--r--spec/models/concerns/resolvable_discussion_spec.rb2
-rw-r--r--spec/models/concerns/resolvable_note_spec.rb2
-rw-r--r--spec/models/concerns/routable_spec.rb2
-rw-r--r--spec/models/concerns/sha_attribute_spec.rb2
-rw-r--r--spec/models/concerns/sortable_spec.rb2
-rw-r--r--spec/models/concerns/spammable_spec.rb2
-rw-r--r--spec/models/concerns/strip_attribute_spec.rb2
-rw-r--r--spec/models/concerns/subscribable_spec.rb2
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb2
-rw-r--r--spec/models/concerns/token_authenticatable_strategies/base_spec.rb2
-rw-r--r--spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb2
-rw-r--r--spec/models/concerns/triggerable_hooks_spec.rb2
-rw-r--r--spec/models/concerns/uniquify_spec.rb2
-rw-r--r--spec/models/container_repository_spec.rb2
-rw-r--r--spec/models/conversational_development_index/metric_spec.rb2
-rw-r--r--spec/models/cycle_analytics/code_spec.rb2
-rw-r--r--spec/models/cycle_analytics/issue_spec.rb2
-rw-r--r--spec/models/cycle_analytics/plan_spec.rb2
-rw-r--r--spec/models/cycle_analytics/production_spec.rb2
-rw-r--r--spec/models/cycle_analytics/review_spec.rb2
-rw-r--r--spec/models/cycle_analytics/staging_spec.rb2
-rw-r--r--spec/models/cycle_analytics/test_spec.rb2
-rw-r--r--spec/models/cycle_analytics_spec.rb2
-rw-r--r--spec/models/deploy_key_spec.rb2
-rw-r--r--spec/models/deploy_keys_project_spec.rb2
-rw-r--r--spec/models/deploy_token_spec.rb2
-rw-r--r--spec/models/deployment_spec.rb2
-rw-r--r--spec/models/diff_discussion_spec.rb2
-rw-r--r--spec/models/diff_note_spec.rb2
-rw-r--r--spec/models/diff_viewer/base_spec.rb2
-rw-r--r--spec/models/diff_viewer/server_side_spec.rb2
-rw-r--r--spec/models/discussion_spec.rb2
-rw-r--r--spec/models/email_spec.rb2
-rw-r--r--spec/models/environment_spec.rb2
-rw-r--r--spec/models/environment_status_spec.rb2
-rw-r--r--spec/models/error_tracking/project_error_tracking_setting_spec.rb28
-rw-r--r--spec/models/event_collection_spec.rb2
-rw-r--r--spec/models/event_spec.rb2
-rw-r--r--spec/models/external_issue_spec.rb2
-rw-r--r--spec/models/fork_network_member_spec.rb2
-rw-r--r--spec/models/fork_network_spec.rb2
-rw-r--r--spec/models/generic_commit_status_spec.rb2
-rw-r--r--spec/models/global_milestone_spec.rb2
-rw-r--r--spec/models/gpg_key_spec.rb2
-rw-r--r--spec/models/gpg_key_subkey_spec.rb2
-rw-r--r--spec/models/gpg_signature_spec.rb2
-rw-r--r--spec/models/group_custom_attribute_spec.rb2
-rw-r--r--spec/models/group_label_spec.rb2
-rw-r--r--spec/models/group_milestone_spec.rb2
-rw-r--r--spec/models/group_spec.rb2
-rw-r--r--spec/models/guest_spec.rb2
-rw-r--r--spec/models/hooks/active_hook_filter_spec.rb2
-rw-r--r--spec/models/hooks/project_hook_spec.rb2
-rw-r--r--spec/models/hooks/service_hook_spec.rb2
-rw-r--r--spec/models/hooks/system_hook_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_log_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_spec.rb2
-rw-r--r--spec/models/identity_spec.rb2
-rw-r--r--spec/models/import_export_upload_spec.rb2
-rw-r--r--spec/models/instance_configuration_spec.rb6
-rw-r--r--spec/models/internal_id_spec.rb2
-rw-r--r--spec/models/issue/metrics_spec.rb2
-rw-r--r--spec/models/issue_collection_spec.rb2
-rw-r--r--spec/models/issue_spec.rb2
-rw-r--r--spec/models/key_spec.rb2
-rw-r--r--spec/models/label_link_spec.rb2
-rw-r--r--spec/models/label_priority_spec.rb2
-rw-r--r--spec/models/label_spec.rb2
-rw-r--r--spec/models/legacy_diff_discussion_spec.rb2
-rw-r--r--spec/models/lfs_download_object_spec.rb2
-rw-r--r--spec/models/lfs_file_lock_spec.rb2
-rw-r--r--spec/models/lfs_object_spec.rb2
-rw-r--r--spec/models/lfs_objects_project_spec.rb2
-rw-r--r--spec/models/license_template_spec.rb15
-rw-r--r--spec/models/list_spec.rb2
-rw-r--r--spec/models/member_spec.rb2
-rw-r--r--spec/models/members/group_member_spec.rb2
-rw-r--r--spec/models/members/project_member_spec.rb2
-rw-r--r--spec/models/merge_request/metrics_spec.rb2
-rw-r--r--spec/models/merge_request_diff_commit_spec.rb2
-rw-r--r--spec/models/merge_request_diff_file_spec.rb2
-rw-r--r--spec/models/merge_request_diff_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb75
-rw-r--r--spec/models/milestone_spec.rb2
-rw-r--r--spec/models/namespace_spec.rb2
-rw-r--r--spec/models/network/graph_spec.rb2
-rw-r--r--spec/models/note_diff_file_spec.rb2
-rw-r--r--spec/models/note_spec.rb2
-rw-r--r--spec/models/notification_recipient_spec.rb2
-rw-r--r--spec/models/notification_setting_spec.rb2
-rw-r--r--spec/models/pages_domain_spec.rb2
-rw-r--r--spec/models/personal_access_token_spec.rb2
-rw-r--r--spec/models/programming_language_spec.rb2
-rw-r--r--spec/models/project_authorization_spec.rb2
-rw-r--r--spec/models/project_auto_devops_spec.rb2
-rw-r--r--spec/models/project_custom_attribute_spec.rb2
-rw-r--r--spec/models/project_deploy_token_spec.rb2
-rw-r--r--spec/models/project_feature_spec.rb2
-rw-r--r--spec/models/project_group_link_spec.rb2
-rw-r--r--spec/models/project_import_state_spec.rb2
-rw-r--r--spec/models/project_label_spec.rb2
-rw-r--r--spec/models/project_services/asana_service_spec.rb2
-rw-r--r--spec/models/project_services/assembla_service_spec.rb2
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb2
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb2
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb2
-rw-r--r--spec/models/project_services/campfire_service_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/issue_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/merge_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/note_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/pipeline_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/push_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/wiki_page_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_notification_service_spec.rb2
-rw-r--r--spec/models/project_services/custom_issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb2
-rw-r--r--spec/models/project_services/emails_on_push_service_spec.rb2
-rw-r--r--spec/models/project_services/external_wiki_service_spec.rb2
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb2
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/irker_service_spec.rb2
-rw-r--r--spec/models/project_services/issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/jira_service_spec.rb2
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb2
-rw-r--r--spec/models/project_services/mattermost_service_spec.rb2
-rw-r--r--spec/models/project_services/mattermost_slash_commands_service_spec.rb2
-rw-r--r--spec/models/project_services/microsoft_teams_service_spec.rb2
-rw-r--r--spec/models/project_services/packagist_service_spec.rb2
-rw-r--r--spec/models/project_services/pipelines_email_service_spec.rb2
-rw-r--r--spec/models/project_services/pivotaltracker_service_spec.rb2
-rw-r--r--spec/models/project_services/pushover_service_spec.rb2
-rw-r--r--spec/models/project_services/redmine_service_spec.rb2
-rw-r--r--spec/models/project_services/slack_service_spec.rb2
-rw-r--r--spec/models/project_services/slack_slash_commands_service_spec.rb2
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb2
-rw-r--r--spec/models/project_services/youtrack_service_spec.rb2
-rw-r--r--spec/models/project_snippet_spec.rb2
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/project_statistics_spec.rb2
-rw-r--r--spec/models/project_team_spec.rb2
-rw-r--r--spec/models/project_wiki_spec.rb2
-rw-r--r--spec/models/protectable_dropdown_spec.rb2
-rw-r--r--spec/models/protected_branch/merge_access_level_spec.rb2
-rw-r--r--spec/models/protected_branch/push_access_level_spec.rb2
-rw-r--r--spec/models/protected_branch_spec.rb2
-rw-r--r--spec/models/protected_tag_spec.rb2
-rw-r--r--spec/models/push_event_payload_spec.rb2
-rw-r--r--spec/models/push_event_spec.rb2
-rw-r--r--spec/models/redirect_route_spec.rb2
-rw-r--r--spec/models/release_spec.rb2
-rw-r--r--spec/models/remote_mirror_spec.rb2
-rw-r--r--spec/models/repository_language_spec.rb2
-rw-r--r--spec/models/repository_spec.rb2
-rw-r--r--spec/models/route_spec.rb2
-rw-r--r--spec/models/sent_notification_spec.rb2
-rw-r--r--spec/models/service_spec.rb2
-rw-r--r--spec/models/snippet_blob_spec.rb2
-rw-r--r--spec/models/snippet_spec.rb2
-rw-r--r--spec/models/spam_log_spec.rb2
-rw-r--r--spec/models/ssh_host_key_spec.rb2
-rw-r--r--spec/models/subscription_spec.rb2
-rw-r--r--spec/models/system_note_metadata_spec.rb2
-rw-r--r--spec/models/term_agreement_spec.rb2
-rw-r--r--spec/models/timelog_spec.rb2
-rw-r--r--spec/models/todo_spec.rb2
-rw-r--r--spec/models/tree_spec.rb2
-rw-r--r--spec/models/trending_project_spec.rb2
-rw-r--r--spec/models/upload_spec.rb2
-rw-r--r--spec/models/user_agent_detail_spec.rb2
-rw-r--r--spec/models/user_callout_spec.rb2
-rw-r--r--spec/models/user_custom_attribute_spec.rb2
-rw-r--r--spec/models/user_interacted_project_spec.rb2
-rw-r--r--spec/models/user_spec.rb2
-rw-r--r--spec/models/wiki_directory_spec.rb2
-rw-r--r--spec/models/wiki_page_spec.rb2
-rw-r--r--spec/presenters/ci/build_runner_presenter_spec.rb38
-rw-r--r--spec/presenters/clusters/cluster_presenter_spec.rb16
-rw-r--r--spec/requests/api/branches_spec.rb26
-rw-r--r--spec/requests/api/project_clusters_spec.rb8
-rw-r--r--spec/services/error_tracking/list_issues_service_spec.rb24
-rw-r--r--spec/services/issues/create_service_spec.rb14
-rw-r--r--spec/services/issues/update_service_spec.rb10
-rw-r--r--spec/services/merge_requests/create_service_spec.rb48
-rw-r--r--spec/services/merge_requests/merge_to_ref_service_spec.rb20
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb41
-rw-r--r--spec/services/projects/after_import_service_spec.rb2
-rw-r--r--spec/services/projects/housekeeping_service_spec.rb13
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb1
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/features/issuable_quick_actions_shared_examples.rb389
-rw-r--r--spec/support/helpers/license_helper.rb8
-rw-r--r--spec/support/helpers/stub_worker.rb9
-rw-r--r--spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/assign_quick_action_shared_examples.rb110
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/award_quick_action_shared_examples.rb63
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb89
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/copy_metadata_quick_action_shared_examples.rb88
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/done_quick_action_shared_examples.rb103
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/estimate_quick_action_shared_examples.rb81
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/label_quick_action_shared_examples.rb83
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/lock_quick_action_shared_examples.rb84
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/milestone_quick_action_shared_examples.rb83
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/relabel_quick_action_shared_examples.rb95
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/remove_estimate_quick_action_shared_examples.rb82
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/remove_milestone_quick_action_shared_examples.rb86
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/remove_time_spent_quick_action_shared_examples.rb82
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/reopen_quick_action_shared_examples.rb86
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/shrug_quick_action_shared_examples.rb60
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/spend_quick_action_shared_examples.rb81
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/subscribe_quick_action_shared_examples.rb84
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/tableflip_quick_action_shared_examples.rb60
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb98
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/title_quick_action_shared_examples.rb85
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/todo_quick_action_shared_examples.rb92
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/unassign_quick_action_shared_examples.rb120
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/unlabel_quick_action_shared_examples.rb102
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/unlock_quick_action_shared_examples.rb87
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/unsubscribe_quick_action_shared_examples.rb86
-rw-r--r--spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/issue/confidential_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/issue/due_quick_action_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/target_branch_quick_action_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/wip_quick_action_shared_examples.rb4
-rw-r--r--spec/uploaders/object_storage_spec.rb2
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb52
-rw-r--r--spec/workers/admin_email_worker_spec.rb2
-rw-r--r--spec/workers/archive_trace_worker_spec.rb2
-rw-r--r--spec/workers/authorized_projects_worker_spec.rb2
-rw-r--r--spec/workers/background_migration_worker_spec.rb2
-rw-r--r--spec/workers/build_coverage_worker_spec.rb2
-rw-r--r--spec/workers/build_finished_worker_spec.rb2
-rw-r--r--spec/workers/build_hooks_worker_spec.rb2
-rw-r--r--spec/workers/build_success_worker_spec.rb2
-rw-r--r--spec/workers/build_trace_sections_worker_spec.rb2
-rw-r--r--spec/workers/ci/archive_traces_cron_worker_spec.rb2
-rw-r--r--spec/workers/ci/build_schedule_worker_spec.rb2
-rw-r--r--spec/workers/cluster_provision_worker_spec.rb2
-rw-r--r--spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb2
-rw-r--r--spec/workers/concerns/application_worker_spec.rb2
-rw-r--r--spec/workers/concerns/cluster_queue_spec.rb2
-rw-r--r--spec/workers/concerns/cronjob_queue_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/notify_upon_death_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/object_importer_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/queue_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb2
-rw-r--r--spec/workers/concerns/pipeline_background_queue_spec.rb2
-rw-r--r--spec/workers/concerns/pipeline_queue_spec.rb2
-rw-r--r--spec/workers/concerns/project_import_options_spec.rb2
-rw-r--r--spec/workers/concerns/repository_check_queue_spec.rb2
-rw-r--r--spec/workers/concerns/waitable_worker_spec.rb2
-rw-r--r--spec/workers/create_gpg_signature_worker_spec.rb2
-rw-r--r--spec/workers/create_note_diff_file_worker_spec.rb2
-rw-r--r--spec/workers/create_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/delete_diff_files_worker_spec.rb2
-rw-r--r--spec/workers/delete_merged_branches_worker_spec.rb2
-rw-r--r--spec/workers/delete_user_worker_spec.rb2
-rw-r--r--spec/workers/deployments/success_worker_spec.rb2
-rw-r--r--spec/workers/detect_repository_languages_worker_spec.rb2
-rw-r--r--spec/workers/email_receiver_worker_spec.rb2
-rw-r--r--spec/workers/emails_on_push_worker_spec.rb2
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb2
-rw-r--r--spec/workers/expire_build_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/expire_build_instance_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/expire_job_cache_worker_spec.rb2
-rw-r--r--spec/workers/expire_pipeline_cache_worker_spec.rb2
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/advance_stage_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_issue_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_note_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb2
-rw-r--r--spec/workers/gitlab_shell_worker_spec.rb2
-rw-r--r--spec/workers/gitlab_usage_ping_worker_spec.rb2
-rw-r--r--spec/workers/group_destroy_worker_spec.rb2
-rw-r--r--spec/workers/hashed_storage/migrator_worker_spec.rb2
-rw-r--r--spec/workers/hashed_storage/project_migrate_worker_spec.rb2
-rw-r--r--spec/workers/invalid_gpg_signature_update_worker_spec.rb2
-rw-r--r--spec/workers/issue_due_scheduler_worker_spec.rb2
-rw-r--r--spec/workers/mail_scheduler/issue_due_worker_spec.rb2
-rw-r--r--spec/workers/mail_scheduler/notification_service_worker_spec.rb2
-rw-r--r--spec/workers/merge_worker_spec.rb2
-rw-r--r--spec/workers/namespaceless_project_destroy_worker_spec.rb2
-rw-r--r--spec/workers/new_issue_worker_spec.rb2
-rw-r--r--spec/workers/new_merge_request_worker_spec.rb2
-rw-r--r--spec/workers/new_note_worker_spec.rb2
-rw-r--r--spec/workers/pages_domain_verification_cron_worker_spec.rb2
-rw-r--r--spec/workers/pages_domain_verification_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_hooks_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_metrics_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_notification_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_process_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_schedule_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_success_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_update_worker_spec.rb2
-rw-r--r--spec/workers/plugin_worker_spec.rb2
-rw-r--r--spec/workers/post_receive_spec.rb2
-rw-r--r--spec/workers/process_commit_worker_spec.rb2
-rw-r--r--spec/workers/project_cache_worker_spec.rb2
-rw-r--r--spec/workers/project_destroy_worker_spec.rb2
-rw-r--r--spec/workers/project_export_worker_spec.rb2
-rw-r--r--spec/workers/propagate_service_template_worker_spec.rb2
-rw-r--r--spec/workers/prune_old_events_worker_spec.rb2
-rw-r--r--spec/workers/prune_web_hook_logs_worker_spec.rb2
-rw-r--r--spec/workers/reactive_caching_worker_spec.rb2
-rw-r--r--spec/workers/rebase_worker_spec.rb2
-rw-r--r--spec/workers/remote_mirror_notification_worker_spec.rb2
-rw-r--r--spec/workers/remove_expired_group_links_worker_spec.rb2
-rw-r--r--spec/workers/remove_expired_members_worker_spec.rb2
-rw-r--r--spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/batch_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/clear_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/dispatch_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/single_repository_worker_spec.rb2
-rw-r--r--spec/workers/repository_cleanup_worker_spec.rb2
-rw-r--r--spec/workers/repository_fork_worker_spec.rb2
-rw-r--r--spec/workers/repository_import_worker_spec.rb2
-rw-r--r--spec/workers/repository_remove_remote_worker_spec.rb2
-rw-r--r--spec/workers/repository_update_remote_mirror_worker_spec.rb2
-rw-r--r--spec/workers/run_pipeline_schedule_worker_spec.rb2
-rw-r--r--spec/workers/stage_update_worker_spec.rb2
-rw-r--r--spec/workers/stuck_ci_jobs_worker_spec.rb2
-rw-r--r--spec/workers/stuck_import_jobs_worker_spec.rb2
-rw-r--r--spec/workers/stuck_merge_jobs_worker_spec.rb2
-rw-r--r--spec/workers/system_hook_push_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/confidential_issue_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/entity_leave_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/group_private_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/private_features_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/project_private_worker_spec.rb2
-rw-r--r--spec/workers/trending_projects_worker_spec.rb2
-rw-r--r--spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb2
-rw-r--r--spec/workers/update_merge_requests_worker_spec.rb2
-rw-r--r--spec/workers/upload_checksum_worker_spec.rb2
-rw-r--r--spec/workers/wait_for_cluster_creation_worker_spec.rb2
-rw-r--r--yarn.lock13
838 files changed, 6930 insertions, 2305 deletions
diff --git a/.eslintignore b/.eslintignore
index f78840e67be..9a5e15c86ae 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -9,5 +9,6 @@
/scripts/
/tmp/
/vendor/
+jest.config.js
karma.config.js
webpack.config.js
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e7918fb6600..ab38c87039e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -249,8 +249,8 @@ package-and-qa:
- ./scripts/trigger-build omnibus
when: manual
only:
- - //@gitlab-org/gitlab-ce
- - //@gitlab-org/gitlab-ee
+ - /.+/@gitlab-org/gitlab-ce
+ - /.+/@gitlab-org/gitlab-ee
# Review docs base
.review-docs: &review-docs
@@ -685,10 +685,10 @@ gitlab:assets:compile:
- public/assets/
<<: *assets-compile-cache
only:
- - //@gitlab-org/gitlab-ce
- - //@gitlab-org/gitlab-ee
- - //@gitlab/gitlabhq
- - //@gitlab/gitlab-ee
+ - /.+/@gitlab-org/gitlab-ce
+ - /.+/@gitlab-org/gitlab-ee
+ - /.+/@gitlab/gitlabhq
+ - /.+/@gitlab/gitlab-ee
tags:
- docker
- gitlab-org
@@ -990,7 +990,7 @@ no_ee_check:
script:
- scripts/no-ee-check
only:
- - //@gitlab-org/gitlab-ce
+ - /.+/@gitlab-org/gitlab-ce
# GitLab Review apps
.review-build-cng-base: &review-build-cng-base
diff --git a/.rubocop.yml b/.rubocop.yml
index 9143966b864..648d59e8062 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -146,6 +146,20 @@ Naming/FileName:
- XSS
- GRPC
+Rails/ApplicationRecord:
+ Enabled: true
+ Exclude:
+ # Models in database migrations should not subclass from ApplicationRecord
+ # as they need to be as decoupled from application code as possible
+ - db/**/*.rb
+ - lib/gitlab/background_migration/**/*.rb
+ - lib/gitlab/database/**/*.rb
+ - spec/**/*.rb
+ - ee/db/**/*.rb
+ - ee/lib/gitlab/background_migration/**/*.rb
+ - ee/lib/ee/gitlab/background_migration/**/*.rb
+ - ee/spec/**/*.rb
+
# GitLab ###################################################################
Gitlab/ModuleWithInstanceVariables:
diff --git a/.scss-lint.yml b/.scss-lint.yml
index 3df66033fa8..2a1fa27fdb5 100644
--- a/.scss-lint.yml
+++ b/.scss-lint.yml
@@ -1,7 +1,9 @@
# Linter Documentation:
# https://github.com/brigade/scss-lint/blob/master/lib/scss_lint/linter/README.md
-scss_files: 'app/assets/stylesheets/**/*.scss'
+scss_files:
+ - 'app/assets/stylesheets/**/*.scss'
+ - 'ee/app/assets/stylesheets/**/*.scss'
exclude:
- 'app/assets/stylesheets/pages/emojis.scss'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 5e57fb89558..034552a83ee 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1.29.0
+1.30.0
diff --git a/app/assets/images/select2-spinner.gif b/app/assets/images/select2-spinner.gif
new file mode 100644
index 00000000000..5b33f7e54f4
--- /dev/null
+++ b/app/assets/images/select2-spinner.gif
Binary files differ
diff --git a/app/assets/images/select2.png b/app/assets/images/select2.png
new file mode 100644
index 00000000000..1d804ffb996
--- /dev/null
+++ b/app/assets/images/select2.png
Binary files differ
diff --git a/app/assets/images/select2x2.png b/app/assets/images/select2x2.png
new file mode 100644
index 00000000000..4bdd5c961d4
--- /dev/null
+++ b/app/assets/images/select2x2.png
Binary files differ
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 0e779e1be9a..58a9605c181 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -170,21 +170,23 @@ export default {
</div>
<gl-loading-icon v-if="showLoadingIcon" class="diff-content loading" />
<template v-else>
- <div v-if="errorMessage" class="diff-viewer">
- <div class="nothing-here-block" v-html="errorMessage"></div>
+ <div :id="`diff-content-${file.file_hash}`">
+ <div v-if="errorMessage" class="diff-viewer">
+ <div class="nothing-here-block" v-html="errorMessage"></div>
+ </div>
+ <div v-else-if="isCollapsed" class="nothing-here-block diff-collapsed">
+ {{ __('This diff is collapsed.') }}
+ <a class="click-to-expand js-click-to-expand" href="#" @click.prevent="handleToggle">{{
+ __('Click to expand it.')
+ }}</a>
+ </div>
+ <diff-content
+ v-else
+ :class="{ hidden: isCollapsed || isFileTooLarge }"
+ :diff-file="file"
+ :help-page-path="helpPagePath"
+ />
</div>
- <div v-else-if="isCollapsed" class="nothing-here-block diff-collapsed">
- {{ __('This diff is collapsed.') }}
- <a class="click-to-expand js-click-to-expand" href="#" @click.prevent="handleToggle">{{
- __('Click to expand it.')
- }}</a>
- </div>
- <diff-content
- v-else
- :class="{ hidden: isCollapsed || isFileTooLarge }"
- :diff-file="file"
- :help-page-path="helpPagePath"
- />
</template>
<div v-if="isFileTooLarge" class="nothing-here-block diff-collapsed js-too-large-diff">
{{ __('This source diff could not be displayed because it is too large.') }}
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index d41d1464166..fda7b7c5fd9 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -11,6 +11,7 @@ import { __, s__, sprintf } from '~/locale';
import { diffViewerModes } from '~/ide/constants';
import EditButton from './edit_button.vue';
import DiffStats from './diff_stats.vue';
+import { scrollToElement } from '~/lib/utils/common_utils';
export default {
components: {
@@ -66,6 +67,9 @@ export default {
hasExpandedDiscussions() {
return this.diffHasExpandedDiscussions(this.diffFile);
},
+ diffContentIDSelector() {
+ return `#diff-content-${this.diffFile.file_hash}`;
+ },
icon() {
if (this.diffFile.submodule) {
return 'archive';
@@ -77,6 +81,11 @@ export default {
if (this.diffFile.submodule) {
return this.diffFile.submodule_tree_url || this.diffFile.submodule_link;
}
+
+ if (!this.discussionPath) {
+ return this.diffContentIDSelector;
+ }
+
return this.discussionPath;
},
filePath() {
@@ -149,6 +158,18 @@ export default {
handleToggleDiscussions() {
this.toggleFileDiscussions(this.diffFile);
},
+ handleFileNameClick(e) {
+ const isLinkToOtherPage =
+ this.diffFile.submodule_tree_url || this.diffFile.submodule_link || this.discussionPath;
+
+ if (!isLinkToOtherPage) {
+ e.preventDefault();
+ const selector = this.diffContentIDSelector;
+
+ scrollToElement(document.querySelector(selector));
+ window.location.hash = selector;
+ }
+ },
},
};
</script>
@@ -168,7 +189,14 @@ export default {
class="diff-toggle-caret append-right-5"
@click.stop="handleToggle"
/>
- <a v-once ref="titleWrapper" :href="titleLink" class="append-right-4 js-title-wrapper">
+ <a
+ v-once
+ id="diffFile.file_path"
+ ref="titleWrapper"
+ class="append-right-4 js-title-wrapper"
+ :href="titleLink"
+ @click="handleFileNameClick"
+ >
<file-icon
:file-name="filePath"
:size="18"
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index a092bdfbc6c..c541ea3445b 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -459,12 +459,7 @@ export default {
class="gl-responsive-table-row"
role="row"
>
- <div
- v-gl-tooltip
- :title="model.name"
- class="table-section section-wrap section-15 text-truncate"
- role="gridcell"
- >
+ <div class="table-section section-wrap section-15 text-truncate" role="gridcell">
<div v-if="!model.isFolder" class="table-mobile-header" role="rowheader">
{{ s__('Environments|Environment') }}
</div>
@@ -473,14 +468,28 @@ export default {
<icon :name="deployIconName" />
</span>
- <span v-if="!model.isFolder" class="environment-name table-mobile-content">
- <a class="qa-environment-link" :href="environmentPath"> {{ model.name }} </a>
+ <span
+ v-if="!model.isFolder"
+ v-gl-tooltip
+ :title="model.name"
+ class="environment-name table-mobile-content"
+ >
+ <a class="qa-environment-link" :href="environmentPath">
+ <span v-if="model.size === 1">{{ model.name }}</span>
+ <span v-else>{{ model.name_without_type }}</span>
+ </a>
<span v-if="isProtected" class="badge badge-success">
{{ s__('Environments|protected') }}
</span>
</span>
-
- <span v-else class="folder-name" role="button" @click="onClickFolder">
+ <span
+ v-else
+ v-gl-tooltip
+ :title="model.folderName"
+ class="folder-name"
+ role="button"
+ @click="onClickFolder"
+ >
<icon :name="folderIconName" class="folder-icon" />
<icon name="folder" class="folder-icon" />
diff --git a/app/assets/javascripts/error_tracking/store/actions.js b/app/assets/javascripts/error_tracking/store/actions.js
index d42e4f145dc..1e754a4f54f 100644
--- a/app/assets/javascripts/error_tracking/store/actions.js
+++ b/app/assets/javascripts/error_tracking/store/actions.js
@@ -20,7 +20,7 @@ export function startPolling({ commit, dispatch }, endpoint) {
commit(types.SET_LOADING, false);
dispatch('stopPolling');
},
- errorCallback: response => {
+ errorCallback: ({ response }) => {
let errorMessage = '';
if (response && response.data && response.data.message) {
errorMessage = response.data.message;
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 1af6b63efc9..59930f8d4a3 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -7,6 +7,7 @@ import axios from './axios_utils';
import { getLocationHash } from './url_utility';
import { convertToCamelCase } from './text_utility';
import { isObject } from './type_utility';
+import BreakpointInstance from '../../breakpoints';
export const getPagePath = (index = 0) => {
const page = $('body').attr('data-page') || '';
@@ -193,16 +194,24 @@ export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
export const isMetaClick = e => e.metaKey || e.ctrlKey || e.which === 2;
export const contentTop = () => {
- const perfBar = $('#js-peek').height() || 0;
- const mrTabsHeight = $('.merge-request-tabs').height() || 0;
- const headerHeight = $('.navbar-gitlab').height() || 0;
- const diffFilesChanged = $('.js-diff-files-changed').height() || 0;
- const diffFileLargeEnoughScreen =
- 'matchMedia' in window ? window.matchMedia('min-width: 768') : true;
+ const perfBar = $('#js-peek').outerHeight() || 0;
+ const mrTabsHeight = $('.merge-request-tabs').outerHeight() || 0;
+ const headerHeight = $('.navbar-gitlab').outerHeight() || 0;
+ const diffFilesChanged = $('.js-diff-files-changed').outerHeight() || 0;
+ const mdScreenOrBigger = ['lg', 'md'].includes(BreakpointInstance.getBreakpointSize());
const diffFileTitleBar =
- (diffFileLargeEnoughScreen && $('.diff-file .file-title-flex-parent:visible').height()) || 0;
+ (mdScreenOrBigger && $('.diff-file .file-title-flex-parent:visible').outerHeight()) || 0;
+ const compareVersionsHeaderHeight =
+ (mdScreenOrBigger && $('.mr-version-controls').outerHeight()) || 0;
- return perfBar + mrTabsHeight + headerHeight + diffFilesChanged + diffFileTitleBar;
+ return (
+ perfBar +
+ mrTabsHeight +
+ headerHeight +
+ diffFilesChanged +
+ diffFileTitleBar +
+ compareVersionsHeaderHeight
+ );
};
export const scrollToElement = element => {
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue
index 41783d311ef..d453dc1fdb7 100644
--- a/app/assets/javascripts/monitoring/components/charts/area.vue
+++ b/app/assets/javascripts/monitoring/components/charts/area.vue
@@ -69,17 +69,17 @@ export default {
appearance && appearance.line && appearance.line.type
? appearance.line.type
: lineTypes.default;
- const lineColor = lineType === lineTypes.threshold ? this.primaryColor : undefined;
+ const lineWidth =
+ appearance && appearance.line && appearance.line.width
+ ? appearance.line.width
+ : undefined;
return {
name: this.formatLegendLabel(query),
data: this.concatenateResults(query.result),
lineStyle: {
type: lineType,
- color: lineColor,
- },
- itemStyle: {
- color: lineColor,
+ width: lineWidth,
},
areaStyle: {
opacity:
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index 869173b6572..55ecf3b5334 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -6,5 +6,4 @@ export const graphTypes = {
export const lineTypes = {
default: 'solid',
- threshold: 'dashed',
};
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index a4b3131c8e4..eccf73e227c 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -189,7 +189,7 @@ export default {
<div
ref="gl-form"
:class="{ 'prepend-top-default append-bottom-default': addSpacingClasses }"
- class="md-area js-vue-markdown-field"
+ class="js-vue-markdown-field md-area position-relative"
>
<markdown-header
:preview-markdown="previewMarkdown"
diff --git a/app/assets/javascripts/vue_shared/components/svg_gradient.vue b/app/assets/javascripts/vue_shared/components/svg_gradient.vue
index cca90af275e..5ce45d492f9 100644
--- a/app/assets/javascripts/vue_shared/components/svg_gradient.vue
+++ b/app/assets/javascripts/vue_shared/components/svg_gradient.vue
@@ -4,10 +4,16 @@ export default {
colors: {
type: Array,
required: true,
+ validator(value) {
+ return value.length === 2;
+ },
},
opacity: {
type: Array,
required: true,
+ validator(value) {
+ return value.length === 2;
+ },
},
identifierName: {
type: String,
diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss
index edf7b26ebaa..5a5601f2fa3 100644
--- a/app/assets/stylesheets/components/related_items_list.scss
+++ b/app/assets/stylesheets/components/related_items_list.scss
@@ -307,6 +307,7 @@ $item-weight-max-width: 48px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
+ line-height: 1.3;
}
.issue-token-state-icon-open,
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 8fc08422d76..d72597a6147 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -462,10 +462,10 @@ img.emoji {
}
/** COMMON POSITIONING CLASSES */
-.position-bottom-0 { bottom: 0; }
-.position-left-0 { left: 0; }
-.position-right-0 { right: 0; }
-.position-top-0 { top: 0; }
+.position-bottom-0 { bottom: 0 !important; }
+.position-left-0 { left: 0 !important; }
+.position-right-0 { right: 0 !important; }
+.position-top-0 { top: 0 !important; }
.drag-handle {
width: 4px;
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 3b1d1d67509..c36c15a85be 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -128,7 +128,7 @@ label {
.form-control {
@include box-shadow(none);
- border-radius: 2px;
+ border-radius: $border-radius-default;
padding: $gl-vert-padding $gl-input-padding;
&.input-short {
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index b2cc3e2428a..7c10de828cd 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -50,10 +50,6 @@
transition: opacity 200ms ease-in-out;
}
-.md-area {
- position: relative;
-}
-
.md-header {
.nav-links {
a {
diff --git a/app/assets/stylesheets/framework/page_title.scss b/app/assets/stylesheets/framework/page_title.scss
index e8302953a63..ad6575761b5 100644
--- a/app/assets/stylesheets/framework/page_title.scss
+++ b/app/assets/stylesheets/framework/page_title.scss
@@ -2,7 +2,6 @@
@extend .d-flex;
@extend .align-items-center;
- padding-top: $gl-padding-top;
border-bottom: 1px solid $border-color;
.page-title {
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb
index 68a2a83f0de..e82756e4643 100644
--- a/app/controllers/clusters/clusters_controller.rb
+++ b/app/controllers/clusters/clusters_controller.rb
@@ -123,25 +123,25 @@ class Clusters::ClustersController < Clusters::BaseController
private
def update_params
- if cluster.managed?
+ if cluster.provided_by_user?
params.require(:cluster).permit(
:enabled,
+ :name,
:environment_scope,
:base_domain,
platform_kubernetes_attributes: [
+ :api_url,
+ :token,
+ :ca_cert,
:namespace
]
)
else
params.require(:cluster).permit(
:enabled,
- :name,
:environment_scope,
:base_domain,
platform_kubernetes_attributes: [
- :api_url,
- :token,
- :ca_cert,
:namespace
]
)
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 909b17e9c8d..7e072788fc9 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -172,8 +172,7 @@ class Projects::BlobController < Projects::ApplicationController
end
if params[:file].present?
- params[:content] = Base64.encode64(params[:file].read)
- params[:encoding] = 'base64'
+ params[:content] = params[:file]
end
@commit_params = {
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 5cf7fa3422d..34cb0416965 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -315,7 +315,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
def serializer
- MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
+ ::Gitlab::GitalyClient.allow_ref_name_caching do
+ MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
+ end
end
def define_edit_vars
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 90d4bc674d9..a80ab3bcd28 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -14,8 +14,6 @@ class SearchController < ApplicationController
layout 'search'
def show
- search_service = SearchService.new(current_user, params)
-
@project = search_service.project
@group = search_service.group
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index 0080123407d..7d419103b1c 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -11,6 +11,7 @@
# parent: Group
# all_available: boolean (defaults to true)
# min_access_level: integer
+# exclude_group_ids: array of integers
#
# Users with full private access can see all groups. The `owned` and `parent`
# params can be used to restrict the groups that are returned.
@@ -29,6 +30,7 @@ class GroupsFinder < UnionFinder
items = all_groups.map do |item|
item = by_parent(item)
item = by_custom_attributes(item)
+ item = exclude_group_ids(item)
item
end
@@ -72,6 +74,12 @@ class GroupsFinder < UnionFinder
end
# rubocop: enable CodeReuse/ActiveRecord
+ def exclude_group_ids(groups)
+ return groups unless params[:exclude_group_ids]
+
+ groups.id_not_in(params[:exclude_group_ids])
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def by_parent(groups)
return groups unless params[:parent]
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 9d028dccad7..7af766c8544 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -118,11 +118,12 @@ module GroupsHelper
end
def parent_group_options(current_group)
- groups = current_user.owned_groups.sort_by(&:human_name).map do |group|
+ exclude_groups = current_group.self_and_descendants.pluck_primary_key
+ exclude_groups << current_group.parent_id if current_group.parent_id
+ groups = GroupsFinder.new(current_user, min_access_level: Gitlab::Access::OWNER, exclude_group_ids: exclude_groups).execute.sort_by(&:human_name).map do |group|
{ id: group.id, text: group.human_name }
end
- groups.delete_if { |group| group[:id] == current_group.id }
groups.to_json
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 09165979b26..69520e33774 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -50,6 +50,10 @@ module SearchHelper
filename
end
+ def search_service
+ @search_service ||= ::SearchService.new(current_user, params)
+ end
+
private
# Autocomplete results for various settings pages
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index 1b78fd04ebb..a3a1748142f 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class AbuseReport < ActiveRecord::Base
+class AbuseReport < ApplicationRecord
include CacheMarkdownField
cache_markdown_field :message, pipeline: :single_line
diff --git a/app/models/appearance.rb b/app/models/appearance.rb
index bdee9b2b73c..2815a117f7f 100644
--- a/app/models/appearance.rb
+++ b/app/models/appearance.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Appearance < ActiveRecord::Base
+class Appearance < ApplicationRecord
include CacheableAttributes
include CacheMarkdownField
include ObjectStorage::BackgroundMove
diff --git a/app/models/application_record.rb b/app/models/application_record.rb
index a3d662d8250..6976185264e 100644
--- a/app/models/application_record.rb
+++ b/app/models/application_record.rb
@@ -7,6 +7,14 @@ class ApplicationRecord < ActiveRecord::Base
where(id: ids)
end
+ def self.id_not_in(ids)
+ where.not(id: ids)
+ end
+
+ def self.pluck_primary_key
+ where(nil).pluck(self.primary_key)
+ end
+
def self.safe_find_or_create_by!(*args)
safe_find_or_create_by(*args).tap do |record|
record.validate! unless record.persisted?
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 9cc7c0a1b97..9e91e4ab4b9 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ApplicationSetting < ActiveRecord::Base
+class ApplicationSetting < ApplicationRecord
include CacheableAttributes
include CacheMarkdownField
include TokenAuthenticatable
diff --git a/app/models/application_setting/term.rb b/app/models/application_setting/term.rb
index 498701ba22b..723540c9b91 100644
--- a/app/models/application_setting/term.rb
+++ b/app/models/application_setting/term.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class ApplicationSetting
- class Term < ActiveRecord::Base
+ class Term < ApplicationRecord
include CacheMarkdownField
has_many :term_agreements
diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb
index 8508c88d406..6ef2914ac11 100644
--- a/app/models/audit_event.rb
+++ b/app/models/audit_event.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class AuditEvent < ActiveRecord::Base
+class AuditEvent < ApplicationRecord
serialize :details, Hash # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :user, foreign_key: :author_id
diff --git a/app/models/award_emoji.rb b/app/models/award_emoji.rb
index ddc516ccb60..e26162f6151 100644
--- a/app/models/award_emoji.rb
+++ b/app/models/award_emoji.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class AwardEmoji < ActiveRecord::Base
+class AwardEmoji < ApplicationRecord
DOWNVOTE_NAME = "thumbsdown".freeze
UPVOTE_NAME = "thumbsup".freeze
diff --git a/app/models/badge.rb b/app/models/badge.rb
index f016654206b..a244ed473de 100644
--- a/app/models/badge.rb
+++ b/app/models/badge.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Badge < ActiveRecord::Base
+class Badge < ApplicationRecord
include FromUnion
# This structure sets the placeholders that the urls
diff --git a/app/models/board.rb b/app/models/board.rb
index 758a71d6903..e08db764f65 100644
--- a/app/models/board.rb
+++ b/app/models/board.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Board < ActiveRecord::Base
+class Board < ApplicationRecord
belongs_to :group
belongs_to :project
diff --git a/app/models/board_group_recent_visit.rb b/app/models/board_group_recent_visit.rb
index f5b75270595..2f1cd830791 100644
--- a/app/models/board_group_recent_visit.rb
+++ b/app/models/board_group_recent_visit.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
# Tracks which boards in a specific group a user has visited
-class BoardGroupRecentVisit < ActiveRecord::Base
+class BoardGroupRecentVisit < ApplicationRecord
belongs_to :user
belongs_to :group
belongs_to :board
diff --git a/app/models/board_project_recent_visit.rb b/app/models/board_project_recent_visit.rb
index 2a1b14b3ae0..236d88e909c 100644
--- a/app/models/board_project_recent_visit.rb
+++ b/app/models/board_project_recent_visit.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
# Tracks which boards in a specific project a user has visited
-class BoardProjectRecentVisit < ActiveRecord::Base
+class BoardProjectRecentVisit < ApplicationRecord
belongs_to :user
belongs_to :project
belongs_to :board
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
index 1c95abdd9ee..18fe2a9624f 100644
--- a/app/models/broadcast_message.rb
+++ b/app/models/broadcast_message.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class BroadcastMessage < ActiveRecord::Base
+class BroadcastMessage < ApplicationRecord
include CacheMarkdownField
include Sortable
diff --git a/app/models/chat_name.rb b/app/models/chat_name.rb
index 03b0af53046..0041595baba 100644
--- a/app/models/chat_name.rb
+++ b/app/models/chat_name.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ChatName < ActiveRecord::Base
+class ChatName < ApplicationRecord
LAST_USED_AT_INTERVAL = 1.hour
belongs_to :service
diff --git a/app/models/chat_team.rb b/app/models/chat_team.rb
index 4e724f9adf7..52b5a7b4a91 100644
--- a/app/models/chat_team.rb
+++ b/app/models/chat_team.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ChatTeam < ActiveRecord::Base
+class ChatTeam < ApplicationRecord
validates :team_id, presence: true
validates :namespace, uniqueness: true
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 59f47effff7..1bd517641ac 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -26,7 +26,8 @@ module Ci
belongs_to :erased_by, class_name: 'User'
RUNNER_FEATURES = {
- upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? }
+ upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? },
+ refspecs: -> (build) { build.merge_request_ref? }
}.freeze
has_one :deployment, as: :deployable, class_name: 'Deployment'
@@ -47,7 +48,8 @@ module Ci
delegate :terminal_specification, to: :runner_session, allow_nil: true
delegate :gitlab_deploy_token, to: :project
delegate :trigger_short_token, to: :trigger_request, allow_nil: true
- delegate :merge_request_event?, to: :pipeline
+ delegate :merge_request_event?, :merge_request_ref?,
+ :legacy_detached_merge_request_pipeline?, to: :pipeline
##
# Since Gitlab 11.5, deployments records started being created right after
diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb
index cd8eb774cf5..f281cbd1d6f 100644
--- a/app/models/ci/build_metadata.rb
+++ b/app/models/ci/build_metadata.rb
@@ -3,7 +3,7 @@
module Ci
# The purpose of this class is to store Build related data that can be disposed.
# Data that should be persisted forever, should be stored with Ci::Build model.
- class BuildMetadata < ActiveRecord::Base
+ class BuildMetadata < ApplicationRecord
extend Gitlab::Ci::Model
include Presentable
include ChronicDurationAttribute
diff --git a/app/models/ci/build_runner_session.rb b/app/models/ci/build_runner_session.rb
index 457d7eeab6a..061eff090f5 100644
--- a/app/models/ci/build_runner_session.rb
+++ b/app/models/ci/build_runner_session.rb
@@ -3,7 +3,7 @@
module Ci
# The purpose of this class is to store Build related runner session.
# Data will be removed after transitioning from running to any state.
- class BuildRunnerSession < ActiveRecord::Base
+ class BuildRunnerSession < ApplicationRecord
extend Gitlab::Ci::Model
self.table_name = 'ci_builds_runner_session'
diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb
index 75017f224a0..0a7a0e0772b 100644
--- a/app/models/ci/build_trace_chunk.rb
+++ b/app/models/ci/build_trace_chunk.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class BuildTraceChunk < ActiveRecord::Base
+ class BuildTraceChunk < ApplicationRecord
include FastDestroyAll
include ::Gitlab::ExclusiveLeaseHelpers
extend Gitlab::Ci::Model
diff --git a/app/models/ci/build_trace_section.rb b/app/models/ci/build_trace_section.rb
index a4bee59c83b..8be42eb48d6 100644
--- a/app/models/ci/build_trace_section.rb
+++ b/app/models/ci/build_trace_section.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class BuildTraceSection < ActiveRecord::Base
+ class BuildTraceSection < ApplicationRecord
extend Gitlab::Ci::Model
belongs_to :build, class_name: 'Ci::Build'
diff --git a/app/models/ci/build_trace_section_name.rb b/app/models/ci/build_trace_section_name.rb
index cbdf3c4b673..c065cfea14e 100644
--- a/app/models/ci/build_trace_section_name.rb
+++ b/app/models/ci/build_trace_section_name.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class BuildTraceSectionName < ActiveRecord::Base
+ class BuildTraceSectionName < ApplicationRecord
extend Gitlab::Ci::Model
belongs_to :project
diff --git a/app/models/ci/group_variable.rb b/app/models/ci/group_variable.rb
index 323ff560564..0e50265c7ba 100644
--- a/app/models/ci/group_variable.rb
+++ b/app/models/ci/group_variable.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class GroupVariable < ActiveRecord::Base
+ class GroupVariable < ApplicationRecord
extend Gitlab::Ci::Model
include HasVariable
include Presentable
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 789bb293811..99512a7c1dd 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class JobArtifact < ActiveRecord::Base
+ class JobArtifact < ApplicationRecord
include AfterCommitQueue
include ObjectStorage::BackgroundMove
extend Gitlab::Ci::Model
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 826b3f82bbf..abac16a138d 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class Pipeline < ActiveRecord::Base
+ class Pipeline < ApplicationRecord
extend Gitlab::Ci::Model
include HasStatus
include Importable
@@ -184,7 +184,7 @@ module Ci
scope :sort_by_merge_request_pipelines, -> do
sql = 'CASE ci_pipelines.source WHEN (?) THEN 0 ELSE 1 END, ci_pipelines.id DESC'
- query = ActiveRecord::Base.send(:sanitize_sql_array, [sql, sources[:merge_request_event]]) # rubocop:disable GitlabSecurity/PublicSend
+ query = ApplicationRecord.send(:sanitize_sql_array, [sql, sources[:merge_request_event]]) # rubocop:disable GitlabSecurity/PublicSend
order(query)
end
@@ -465,9 +465,9 @@ module Ci
end
def latest?
- return false unless ref && commit.present?
+ return false unless git_ref && commit.present?
- project.commit(ref) == commit
+ project.commit(git_ref) == commit
end
def retried
@@ -738,6 +738,10 @@ module Ci
triggered_by_merge_request? && target_sha.nil?
end
+ def legacy_detached_merge_request_pipeline?
+ detached_merge_request_pipeline? && !merge_request_ref?
+ end
+
def merge_request_pipeline?
triggered_by_merge_request? && target_sha.present?
end
@@ -746,6 +750,10 @@ module Ci
triggered_by_merge_request? && target_sha == merge_request.target_branch_sha
end
+ def merge_request_ref?
+ MergeRequest.merge_request_ref?(ref)
+ end
+
def matches_sha_or_source_sha?(sha)
self.sha == sha || self.source_sha == sha
end
@@ -781,16 +789,18 @@ module Ci
end
def git_ref
- if merge_request_event?
- ##
- # In the future, we're going to change this ref to
- # merge request's merged reference, such as "refs/merge-requests/:iid/merge".
- # In order to do that, we have to update GitLab-Runner's source pulling
- # logic.
- # See https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1092
- Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
- else
- super
+ strong_memoize(:git_ref) do
+ if merge_request_event?
+ ##
+ # In the future, we're going to change this ref to
+ # merge request's merged reference, such as "refs/merge-requests/:iid/merge".
+ # In order to do that, we have to update GitLab-Runner's source pulling
+ # logic.
+ # See https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1092
+ Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
+ else
+ super
+ end
end
end
diff --git a/app/models/ci/pipeline_chat_data.rb b/app/models/ci/pipeline_chat_data.rb
index 8d37500fec5..65466a8c6f8 100644
--- a/app/models/ci/pipeline_chat_data.rb
+++ b/app/models/ci/pipeline_chat_data.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class PipelineChatData < ActiveRecord::Base
+ class PipelineChatData < ApplicationRecord
self.table_name = 'ci_pipeline_chat_data'
belongs_to :chat_name
diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb
index 1c1f203bdb2..1454b2dfb39 100644
--- a/app/models/ci/pipeline_schedule.rb
+++ b/app/models/ci/pipeline_schedule.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class PipelineSchedule < ActiveRecord::Base
+ class PipelineSchedule < ApplicationRecord
extend Gitlab::Ci::Model
include Importable
include IgnorableColumn
diff --git a/app/models/ci/pipeline_schedule_variable.rb b/app/models/ci/pipeline_schedule_variable.rb
index fbb9987cab2..be6e5e76c31 100644
--- a/app/models/ci/pipeline_schedule_variable.rb
+++ b/app/models/ci/pipeline_schedule_variable.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class PipelineScheduleVariable < ActiveRecord::Base
+ class PipelineScheduleVariable < ApplicationRecord
extend Gitlab::Ci::Model
include HasVariable
diff --git a/app/models/ci/pipeline_variable.rb b/app/models/ci/pipeline_variable.rb
index 08514d6af4e..51a6272e1ff 100644
--- a/app/models/ci/pipeline_variable.rb
+++ b/app/models/ci/pipeline_variable.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class PipelineVariable < ActiveRecord::Base
+ class PipelineVariable < ApplicationRecord
extend Gitlab::Ci::Model
include HasVariable
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 43f040a91ae..07d00503861 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class Runner < ActiveRecord::Base
+ class Runner < ApplicationRecord
extend Gitlab::Ci::Model
include Gitlab::SQL::Pattern
include IgnorableColumn
diff --git a/app/models/ci/runner_namespace.rb b/app/models/ci/runner_namespace.rb
index 22b80b98551..6903e8a21a1 100644
--- a/app/models/ci/runner_namespace.rb
+++ b/app/models/ci/runner_namespace.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class RunnerNamespace < ActiveRecord::Base
+ class RunnerNamespace < ApplicationRecord
extend Gitlab::Ci::Model
belongs_to :runner, inverse_of: :runner_namespaces, validate: true
diff --git a/app/models/ci/runner_project.rb b/app/models/ci/runner_project.rb
index 1a718d24141..f5bd50dc5a3 100644
--- a/app/models/ci/runner_project.rb
+++ b/app/models/ci/runner_project.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class RunnerProject < ActiveRecord::Base
+ class RunnerProject < ApplicationRecord
extend Gitlab::Ci::Model
belongs_to :runner, inverse_of: :runner_projects
diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb
index 098f5189517..b25b0369666 100644
--- a/app/models/ci/stage.rb
+++ b/app/models/ci/stage.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class Stage < ActiveRecord::Base
+ class Stage < ApplicationRecord
extend Gitlab::Ci::Model
include Importable
include HasStatus
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index 637148c4ce4..8927bb9bc18 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class Trigger < ActiveRecord::Base
+ class Trigger < ApplicationRecord
extend Gitlab::Ci::Model
include IgnorableColumn
include Presentable
diff --git a/app/models/ci/trigger_request.rb b/app/models/ci/trigger_request.rb
index 0b52c690e93..5daf3dd192d 100644
--- a/app/models/ci/trigger_request.rb
+++ b/app/models/ci/trigger_request.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class TriggerRequest < ActiveRecord::Base
+ class TriggerRequest < ApplicationRecord
extend Gitlab::Ci::Model
belongs_to :trigger
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index 64836ea4fa4..a77bbef0fca 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Ci
- class Variable < ActiveRecord::Base
+ class Variable < ApplicationRecord
extend Gitlab::Ci::Model
include HasVariable
include Presentable
diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb
index c758577815a..ac0e7eb03bc 100644
--- a/app/models/clusters/applications/cert_manager.rb
+++ b/app/models/clusters/applications/cert_manager.rb
@@ -2,7 +2,7 @@
module Clusters
module Applications
- class CertManager < ActiveRecord::Base
+ class CertManager < ApplicationRecord
VERSION = 'v0.5.2'.freeze
self.table_name = 'clusters_applications_cert_managers'
diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb
index 423071ec024..71aff00077d 100644
--- a/app/models/clusters/applications/helm.rb
+++ b/app/models/clusters/applications/helm.rb
@@ -4,7 +4,7 @@ require 'openssl'
module Clusters
module Applications
- class Helm < ActiveRecord::Base
+ class Helm < ApplicationRecord
self.table_name = 'clusters_applications_helm'
attr_encrypted :ca_key,
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index 567f1a2267f..376d54aab2c 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -2,7 +2,7 @@
module Clusters
module Applications
- class Ingress < ActiveRecord::Base
+ class Ingress < ApplicationRecord
VERSION = '1.1.2'.freeze
self.table_name = 'clusters_applications_ingress'
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb
index 7efcc175f9f..f86ff3551a1 100644
--- a/app/models/clusters/applications/jupyter.rb
+++ b/app/models/clusters/applications/jupyter.rb
@@ -2,7 +2,7 @@
module Clusters
module Applications
- class Jupyter < ActiveRecord::Base
+ class Jupyter < ApplicationRecord
VERSION = '0.9-174bbd5'.freeze
self.table_name = 'clusters_applications_jupyter'
diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb
index 8afd548f3e3..f7e54833296 100644
--- a/app/models/clusters/applications/knative.rb
+++ b/app/models/clusters/applications/knative.rb
@@ -2,7 +2,7 @@
module Clusters
module Applications
- class Knative < ActiveRecord::Base
+ class Knative < ApplicationRecord
VERSION = '0.3.0'.freeze
REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze
METRICS_CONFIG = 'https://storage.googleapis.com/triggermesh-charts/istio-metrics.yaml'.freeze
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index fa7ce363531..954c29da196 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -2,7 +2,7 @@
module Clusters
module Applications
- class Prometheus < ActiveRecord::Base
+ class Prometheus < ApplicationRecord
include PrometheusAdapter
VERSION = '6.7.3'
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index ec8f5cc40c0..8cb81bfcbe4 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -2,7 +2,7 @@
module Clusters
module Applications
- class Runner < ActiveRecord::Base
+ class Runner < ApplicationRecord
VERSION = '0.3.0'.freeze
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 5156c7d7514..4262c03498d 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -1,22 +1,24 @@
# frozen_string_literal: true
module Clusters
- class Cluster < ActiveRecord::Base
+ class Cluster < ApplicationRecord
include Presentable
include Gitlab::Utils::StrongMemoize
include FromUnion
self.table_name = 'clusters'
+ PROJECT_ONLY_APPLICATIONS = {
+ Applications::Jupyter.application_name => Applications::Jupyter,
+ Applications::Knative.application_name => Applications::Knative,
+ Applications::Prometheus.application_name => Applications::Prometheus
+ }.freeze
APPLICATIONS = {
Applications::Helm.application_name => Applications::Helm,
Applications::Ingress.application_name => Applications::Ingress,
Applications::CertManager.application_name => Applications::CertManager,
- Applications::Prometheus.application_name => Applications::Prometheus,
- Applications::Runner.application_name => Applications::Runner,
- Applications::Jupyter.application_name => Applications::Jupyter,
- Applications::Knative.application_name => Applications::Knative
- }.freeze
+ Applications::Runner.application_name => Applications::Runner
+ }.merge(PROJECT_ONLY_APPLICATIONS).freeze
DEFAULT_ENVIRONMENT = '*'.freeze
KUBE_INGRESS_BASE_DOMAIN = 'KUBE_INGRESS_BASE_DOMAIN'.freeze
@@ -70,6 +72,7 @@ module Clusters
delegate :external_hostname, to: :application_ingress, prefix: true, allow_nil: true
alias_attribute :base_domain, :domain
+ alias_attribute :provided_by_user?, :user?
enum cluster_type: {
instance_type: 1,
@@ -149,10 +152,6 @@ module Clusters
return platform_kubernetes if kubernetes?
end
- def managed?
- !user?
- end
-
def all_projects
if project_type?
projects
diff --git a/app/models/clusters/group.rb b/app/models/clusters/group.rb
index 2b08a9e47f0..27f39b53579 100644
--- a/app/models/clusters/group.rb
+++ b/app/models/clusters/group.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Clusters
- class Group < ActiveRecord::Base
+ class Group < ApplicationRecord
self.table_name = 'cluster_groups'
belongs_to :cluster, class_name: 'Clusters::Cluster'
diff --git a/app/models/clusters/kubernetes_namespace.rb b/app/models/clusters/kubernetes_namespace.rb
index 7fc75e00cd0..b0c4900546e 100644
--- a/app/models/clusters/kubernetes_namespace.rb
+++ b/app/models/clusters/kubernetes_namespace.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Clusters
- class KubernetesNamespace < ActiveRecord::Base
+ class KubernetesNamespace < ApplicationRecord
include Gitlab::Kubernetes
self.table_name = 'clusters_kubernetes_namespaces'
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 7786b48429c..2ae141190a8 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -2,7 +2,7 @@
module Clusters
module Platforms
- class Kubernetes < ActiveRecord::Base
+ class Kubernetes < ApplicationRecord
include Gitlab::Kubernetes
include ReactiveCaching
include EnumWithNil
@@ -54,7 +54,7 @@ module Clusters
delegate :project, to: :cluster, allow_nil: true
delegate :enabled?, to: :cluster, allow_nil: true
- delegate :managed?, to: :cluster, allow_nil: true
+ delegate :provided_by_user?, to: :cluster, allow_nil: true
delegate :allow_user_defined_namespace?, to: :cluster, allow_nil: true
delegate :kubernetes_namespace, to: :cluster
@@ -219,7 +219,7 @@ module Clusters
end
def prevent_modification
- return unless managed?
+ return if provided_by_user?
if api_url_changed? || token_changed? || ca_pem_changed?
errors.add(:base, _('Cannot modify managed Kubernetes cluster'))
diff --git a/app/models/clusters/project.rb b/app/models/clusters/project.rb
index 15092b1c9d2..d2b68b3f117 100644
--- a/app/models/clusters/project.rb
+++ b/app/models/clusters/project.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Clusters
- class Project < ActiveRecord::Base
+ class Project < ApplicationRecord
self.table_name = 'cluster_projects'
belongs_to :cluster, class_name: 'Clusters::Cluster'
diff --git a/app/models/clusters/providers/gcp.rb b/app/models/clusters/providers/gcp.rb
index 16b59cd9d14..390748bf252 100644
--- a/app/models/clusters/providers/gcp.rb
+++ b/app/models/clusters/providers/gcp.rb
@@ -2,7 +2,7 @@
module Clusters
module Providers
- class Gcp < ActiveRecord::Base
+ class Gcp < ApplicationRecord
self.table_name = 'cluster_providers_gcp'
belongs_to :cluster, inverse_of: :provider_gcp, class_name: 'Clusters::Cluster'
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 5f66a661324..f97dc38dab7 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class CommitStatus < ActiveRecord::Base
+class CommitStatus < ApplicationRecord
include HasStatus
include Importable
include AfterCommitQueue
diff --git a/app/models/concerns/atomic_internal_id.rb b/app/models/concerns/atomic_internal_id.rb
index 4e15b60ccd1..ab3d9e923c0 100644
--- a/app/models/concerns/atomic_internal_id.rb
+++ b/app/models/concerns/atomic_internal_id.rb
@@ -7,7 +7,7 @@
#
# For example, let's generate internal ids for Issue per Project:
# ```
-# class Issue < ActiveRecord::Base
+# class Issue < ApplicationRecord
# has_internal_id :iid, scope: :project, init: ->(s) { s.project.issues.maximum(:iid) }
# end
# ```
diff --git a/app/models/concerns/ignorable_column.rb b/app/models/concerns/ignorable_column.rb
index 5c1f7dfcd2a..3bec44dc79b 100644
--- a/app/models/concerns/ignorable_column.rb
+++ b/app/models/concerns/ignorable_column.rb
@@ -5,7 +5,7 @@
#
# Example:
#
-# class User < ActiveRecord::Base
+# class User < ApplicationRecord
# include IgnorableColumn
#
# ignore_column :updated_at
diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb
index 614c3242874..b140fca9b83 100644
--- a/app/models/concerns/participable.rb
+++ b/app/models/concerns/participable.rb
@@ -7,7 +7,7 @@
#
# Usage:
#
-# class Issue < ActiveRecord::Base
+# class Issue < ApplicationRecord
# include Participable
#
# # ...
diff --git a/app/models/concerns/reactive_caching.rb b/app/models/concerns/reactive_caching.rb
index d2ead7130e5..1ab3b3ddc46 100644
--- a/app/models/concerns/reactive_caching.rb
+++ b/app/models/concerns/reactive_caching.rb
@@ -7,7 +7,7 @@
#
# Example of use:
#
-# class Foo < ActiveRecord::Base
+# class Foo < ApplicationRecord
# include ReactiveCaching
#
# self.reactive_cache_key = ->(thing) { ["foo", thing.id] }
diff --git a/app/models/concerns/sha_attribute.rb b/app/models/concerns/sha_attribute.rb
index a479bef993c..70ac873a030 100644
--- a/app/models/concerns/sha_attribute.rb
+++ b/app/models/concerns/sha_attribute.rb
@@ -39,7 +39,7 @@ module ShaAttribute
end
def database_exists?
- ActiveRecord::Base.connection
+ ApplicationRecord.connection
true
rescue
diff --git a/app/models/concerns/strip_attribute.rb b/app/models/concerns/strip_attribute.rb
index c9f5ba7793d..8f6a6244dd3 100644
--- a/app/models/concerns/strip_attribute.rb
+++ b/app/models/concerns/strip_attribute.rb
@@ -6,7 +6,7 @@
#
# Usage:
#
-# class Milestone < ActiveRecord::Base
+# class Milestone < ApplicationRecord
# strip_attributes :title
# end
#
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index cf057d774cf..39e12ac2b06 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ContainerRepository < ActiveRecord::Base
+class ContainerRepository < ApplicationRecord
include Gitlab::Utils::StrongMemoize
belongs_to :project
diff --git a/app/models/conversational_development_index/metric.rb b/app/models/conversational_development_index/metric.rb
index c54537572d6..b91123be87e 100644
--- a/app/models/conversational_development_index/metric.rb
+++ b/app/models/conversational_development_index/metric.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module ConversationalDevelopmentIndex
- class Metric < ActiveRecord::Base
+ class Metric < ApplicationRecord
include Presentable
self.table_name = 'conversational_development_index_metrics'
diff --git a/app/models/deploy_keys_project.rb b/app/models/deploy_keys_project.rb
index 71fd02fac86..15906ed8e06 100644
--- a/app/models/deploy_keys_project.rb
+++ b/app/models/deploy_keys_project.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class DeployKeysProject < ActiveRecord::Base
+class DeployKeysProject < ApplicationRecord
belongs_to :project
belongs_to :deploy_key, inverse_of: :deploy_keys_projects
diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb
index e3524305346..b0e570f52ba 100644
--- a/app/models/deploy_token.rb
+++ b/app/models/deploy_token.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class DeployToken < ActiveRecord::Base
+class DeployToken < ApplicationRecord
include Expirable
include TokenAuthenticatable
include PolicyActor
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 428edfd88de..d847a0a11e4 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Deployment < ActiveRecord::Base
+class Deployment < ApplicationRecord
include AtomicInternalId
include IidRoutes
include AfterCommitQueue
diff --git a/app/models/email.rb b/app/models/email.rb
index 7c33c5c7e64..0ddaa049c3b 100644
--- a/app/models/email.rb
+++ b/app/models/email.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Email < ActiveRecord::Base
+class Email < ApplicationRecord
include Sortable
include Gitlab::SQL::Pattern
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 3d909cc8e5c..25373c7a1f7 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Environment < ActiveRecord::Base
+class Environment < ApplicationRecord
include Gitlab::Utils::StrongMemoize
# Used to generate random suffixes for the slug
LETTERS = 'a'..'z'
diff --git a/app/models/epic.rb b/app/models/epic.rb
index ccd10593434..3693db1de33 100644
--- a/app/models/epic.rb
+++ b/app/models/epic.rb
@@ -2,7 +2,7 @@
# Placeholder class for model that is implemented in EE
# It reserves '&' as a reference prefix, but the table does not exists in CE
-class Epic < ActiveRecord::Base
+class Epic < ApplicationRecord
def self.link_reference_pattern
nil
end
diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb
index 1e2bd3bda7f..70954bf8b05 100644
--- a/app/models/error_tracking/project_error_tracking_setting.rb
+++ b/app/models/error_tracking/project_error_tracking_setting.rb
@@ -1,10 +1,13 @@
# frozen_string_literal: true
module ErrorTracking
- class ProjectErrorTrackingSetting < ActiveRecord::Base
+ class ProjectErrorTrackingSetting < ApplicationRecord
include Gitlab::Utils::StrongMemoize
include ReactiveCaching
+ SENTRY_API_ERROR_TYPE_MISSING_KEYS = 'missing_keys_in_sentry_response'
+ SENTRY_API_ERROR_TYPE_NON_20X_RESPONSE = 'non_20x_response_from_sentry'
+
API_URL_PATH_REGEXP = %r{
\A
(?<prefix>/api/0/projects/+)
@@ -90,7 +93,9 @@ module ErrorTracking
{ issues: sentry_client.list_issues(**opts.symbolize_keys) }
end
rescue Sentry::Client::Error => e
- { error: e.message }
+ { error: e.message, error_type: SENTRY_API_ERROR_TYPE_NON_20X_RESPONSE }
+ rescue Sentry::Client::MissingKeysError => e
+ { error: e.message, error_type: SENTRY_API_ERROR_TYPE_MISSING_KEYS }
end
# http://HOST/api/0/projects/ORG/PROJECT
diff --git a/app/models/event.rb b/app/models/event.rb
index 6a35bca72c5..593acf5edfe 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Event < ActiveRecord::Base
+class Event < ApplicationRecord
include Sortable
include IgnorableColumn
include FromUnion
diff --git a/app/models/fork_network.rb b/app/models/fork_network.rb
index 1b9bf93cbbc..0323a8d222a 100644
--- a/app/models/fork_network.rb
+++ b/app/models/fork_network.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ForkNetwork < ActiveRecord::Base
+class ForkNetwork < ApplicationRecord
belongs_to :root_project, class_name: 'Project'
has_many :fork_network_members
has_many :projects, through: :fork_network_members
diff --git a/app/models/fork_network_member.rb b/app/models/fork_network_member.rb
index 36c66f21b0b..f18c306cf91 100644
--- a/app/models/fork_network_member.rb
+++ b/app/models/fork_network_member.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ForkNetworkMember < ActiveRecord::Base
+class ForkNetworkMember < ApplicationRecord
belongs_to :fork_network
belongs_to :project
belongs_to :forked_from_project, class_name: 'Project'
diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb
index 077afffd358..116beac5c2a 100644
--- a/app/models/gpg_key.rb
+++ b/app/models/gpg_key.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class GpgKey < ActiveRecord::Base
+class GpgKey < ApplicationRecord
KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze
KEY_SUFFIX = '-----END PGP PUBLIC KEY BLOCK-----'.freeze
diff --git a/app/models/gpg_key_subkey.rb b/app/models/gpg_key_subkey.rb
index 440b588bc78..110bf451136 100644
--- a/app/models/gpg_key_subkey.rb
+++ b/app/models/gpg_key_subkey.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class GpgKeySubkey < ActiveRecord::Base
+class GpgKeySubkey < ApplicationRecord
include ShaAttribute
sha_attribute :keyid
diff --git a/app/models/group_custom_attribute.rb b/app/models/group_custom_attribute.rb
index 22f14885657..5ac6e5f2550 100644
--- a/app/models/group_custom_attribute.rb
+++ b/app/models/group_custom_attribute.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class GroupCustomAttribute < ActiveRecord::Base
+class GroupCustomAttribute < ApplicationRecord
belongs_to :group
validates :group, :key, :value, presence: true
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 1a8662db9fb..daf7ff4b771 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class WebHook < ActiveRecord::Base
+class WebHook < ApplicationRecord
include Sortable
attr_encrypted :token,
diff --git a/app/models/hooks/web_hook_log.rb b/app/models/hooks/web_hook_log.rb
index 2d9f7594e8c..cfb1f3ec63b 100644
--- a/app/models/hooks/web_hook_log.rb
+++ b/app/models/hooks/web_hook_log.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class WebHookLog < ActiveRecord::Base
+class WebHookLog < ApplicationRecord
belongs_to :web_hook
serialize :request_headers, Hash # rubocop:disable Cop/ActiveRecordSerialize
diff --git a/app/models/identity.rb b/app/models/identity.rb
index acdde4f296b..8322b9bf35f 100644
--- a/app/models/identity.rb
+++ b/app/models/identity.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Identity < ActiveRecord::Base
+class Identity < ApplicationRecord
include Sortable
include CaseSensitivity
diff --git a/app/models/identity/uniqueness_scopes.rb b/app/models/identity/uniqueness_scopes.rb
index 674b735903f..ce68371ae87 100644
--- a/app/models/identity/uniqueness_scopes.rb
+++ b/app/models/identity/uniqueness_scopes.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Identity < ActiveRecord::Base
+class Identity < ApplicationRecord
# This module and method are defined in a separate file to allow EE to
# redefine the `scopes` method before it is used in the `Identity` model.
module UniquenessScopes
diff --git a/app/models/import_export_upload.rb b/app/models/import_export_upload.rb
index f0cc5aafcd4..60f5491849a 100644
--- a/app/models/import_export_upload.rb
+++ b/app/models/import_export_upload.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ImportExportUpload < ActiveRecord::Base
+class ImportExportUpload < ApplicationRecord
include WithUploads
include ObjectStorage::BackgroundMove
diff --git a/app/models/internal_id.rb b/app/models/internal_id.rb
index e75c6eb2331..3f2d368a3f2 100644
--- a/app/models/internal_id.rb
+++ b/app/models/internal_id.rb
@@ -15,7 +15,7 @@
# In order to leverage InternalId for other usages, the idea is to
# * Add `usage` value to enum
# * (Optionally) add columns to `internal_ids` if needed for scope.
-class InternalId < ActiveRecord::Base
+class InternalId < ApplicationRecord
belongs_to :project
belongs_to :namespace
diff --git a/app/models/issue.rb b/app/models/issue.rb
index deab53d25e7..97c6dcc4745 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -2,7 +2,7 @@
require 'carrierwave/orm/activerecord'
-class Issue < ActiveRecord::Base
+class Issue < ApplicationRecord
include AtomicInternalId
include IidRoutes
include Issuable
diff --git a/app/models/issue/metrics.rb b/app/models/issue/metrics.rb
index 0f5ee957ec9..8010cbc3d78 100644
--- a/app/models/issue/metrics.rb
+++ b/app/models/issue/metrics.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Issue::Metrics < ActiveRecord::Base
+class Issue::Metrics < ApplicationRecord
belongs_to :issue
def record!
diff --git a/app/models/issue_assignee.rb b/app/models/issue_assignee.rb
index 400c0256945..fbd9be1fb43 100644
--- a/app/models/issue_assignee.rb
+++ b/app/models/issue_assignee.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class IssueAssignee < ActiveRecord::Base
+class IssueAssignee < ApplicationRecord
belongs_to :issue
belongs_to :assignee, class_name: "User", foreign_key: :user_id
end
diff --git a/app/models/key.rb b/app/models/key.rb
index 8f93418b88b..b097be8cc89 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -2,7 +2,7 @@
require 'digest/md5'
-class Key < ActiveRecord::Base
+class Key < ApplicationRecord
include AfterCommitQueue
include Sortable
diff --git a/app/models/label.rb b/app/models/label.rb
index 96bdb7f17c5..024daeb4fae 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Label < ActiveRecord::Base
+class Label < ApplicationRecord
include CacheMarkdownField
include Referable
include Subscribable
diff --git a/app/models/label_link.rb b/app/models/label_link.rb
index 1d93a55e8e9..ffc0afd8e85 100644
--- a/app/models/label_link.rb
+++ b/app/models/label_link.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class LabelLink < ActiveRecord::Base
+class LabelLink < ApplicationRecord
include Importable
belongs_to :target, polymorphic: true, inverse_of: :label_links # rubocop:disable Cop/PolymorphicAssociations
diff --git a/app/models/label_priority.rb b/app/models/label_priority.rb
index 8ed8bb7577f..8f8f36efbfe 100644
--- a/app/models/label_priority.rb
+++ b/app/models/label_priority.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class LabelPriority < ActiveRecord::Base
+class LabelPriority < ApplicationRecord
belongs_to :project
belongs_to :label
diff --git a/app/models/lfs_file_lock.rb b/app/models/lfs_file_lock.rb
index 431d37e12e9..624b1d02e1a 100644
--- a/app/models/lfs_file_lock.rb
+++ b/app/models/lfs_file_lock.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class LfsFileLock < ActiveRecord::Base
+class LfsFileLock < ApplicationRecord
belongs_to :project
belongs_to :user
diff --git a/app/models/lfs_object.rb b/app/models/lfs_object.rb
index 69c563545bb..e1aac691a64 100644
--- a/app/models/lfs_object.rb
+++ b/app/models/lfs_object.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class LfsObject < ActiveRecord::Base
+class LfsObject < ApplicationRecord
include AfterCommitQueue
include ObjectStorage::BackgroundMove
diff --git a/app/models/lfs_objects_project.rb b/app/models/lfs_objects_project.rb
index 353602800d7..f9afb18c1d7 100644
--- a/app/models/lfs_objects_project.rb
+++ b/app/models/lfs_objects_project.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class LfsObjectsProject < ActiveRecord::Base
+class LfsObjectsProject < ApplicationRecord
belongs_to :project
belongs_to :lfs_object
diff --git a/app/models/list.rb b/app/models/list.rb
index 682af761ba0..17b1a8510cf 100644
--- a/app/models/list.rb
+++ b/app/models/list.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class List < ActiveRecord::Base
+class List < ApplicationRecord
belongs_to :board
belongs_to :label
diff --git a/app/models/member.rb b/app/models/member.rb
index 5dbc0c2eec9..8a06bff51b5 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Member < ActiveRecord::Base
+class Member < ApplicationRecord
include AfterCommitQueue
include Sortable
include Importable
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 19557fd476e..f6b83453c2a 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class MergeRequest < ActiveRecord::Base
+class MergeRequest < ApplicationRecord
include AtomicInternalId
include IidRoutes
include Issuable
@@ -807,8 +807,7 @@ class MergeRequest < ActiveRecord::Base
end
def mergeable_to_ref?
- return false if merged?
- return false if broken?
+ return false unless mergeable_state?(skip_ci_check: true, skip_discussions_check: true)
# Given the `merge_ref_path` will have the same
# state the `target_branch` would have. Ideally
@@ -1129,6 +1128,10 @@ class MergeRequest < ActiveRecord::Base
"refs/#{Repository::REF_MERGE_REQUEST}/#{iid}/merge"
end
+ def self.merge_request_ref?(ref)
+ ref.start_with?("refs/#{Repository::REF_MERGE_REQUEST}/")
+ end
+
def in_locked_state
begin
lock_mr
@@ -1339,7 +1342,7 @@ class MergeRequest < ActiveRecord::Base
end
def has_commits?
- merge_request_diff && commits_count > 0
+ merge_request_diff && commits_count.to_i > 0
end
def has_no_commits?
diff --git a/app/models/merge_request/metrics.rb b/app/models/merge_request/metrics.rb
index 65e94a97b0a..05f8e18a2c1 100644
--- a/app/models/merge_request/metrics.rb
+++ b/app/models/merge_request/metrics.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class MergeRequest::Metrics < ActiveRecord::Base
+class MergeRequest::Metrics < ApplicationRecord
belongs_to :merge_request
belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :pipeline_id
belongs_to :latest_closed_by, class_name: 'User'
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 2143571d1d4..ac8d3b98266 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class MergeRequestDiff < ActiveRecord::Base
+class MergeRequestDiff < ApplicationRecord
include Sortable
include Importable
include ManualInverseAssociation
diff --git a/app/models/merge_request_diff_commit.rb b/app/models/merge_request_diff_commit.rb
index 4ad3690512d..b897bbc8cf5 100644
--- a/app/models/merge_request_diff_commit.rb
+++ b/app/models/merge_request_diff_commit.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class MergeRequestDiffCommit < ActiveRecord::Base
+class MergeRequestDiffCommit < ApplicationRecord
include ShaAttribute
belongs_to :merge_request_diff
diff --git a/app/models/merge_request_diff_file.rb b/app/models/merge_request_diff_file.rb
index 16ec4ed470f..01ee82ae398 100644
--- a/app/models/merge_request_diff_file.rb
+++ b/app/models/merge_request_diff_file.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class MergeRequestDiffFile < ActiveRecord::Base
+class MergeRequestDiffFile < ApplicationRecord
include Gitlab::EncodingHelper
include DiffFile
diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb
index 242b65bedc0..61af50841ee 100644
--- a/app/models/merge_requests_closing_issues.rb
+++ b/app/models/merge_requests_closing_issues.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class MergeRequestsClosingIssues < ActiveRecord::Base
+class MergeRequestsClosingIssues < ApplicationRecord
belongs_to :merge_request
belongs_to :issue
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index a3831ae3fa8..b4aad9e512e 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Milestone < ActiveRecord::Base
+class Milestone < ApplicationRecord
# Represents a "No Milestone" state used for filtering Issues and Merge
# Requests that have no milestone assigned.
MilestoneStruct = Struct.new(:title, :name, :id)
diff --git a/app/models/note.rb b/app/models/note.rb
index 2c9980b1a0d..081d6f91230 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -3,7 +3,7 @@
# A note on the root of an issue, merge request, commit, or snippet.
#
# A note of this type is never resolvable.
-class Note < ActiveRecord::Base
+class Note < ApplicationRecord
extend ActiveModel::Naming
include Participable
include Mentionable
diff --git a/app/models/note_diff_file.rb b/app/models/note_diff_file.rb
index e369122003e..9afb94c869a 100644
--- a/app/models/note_diff_file.rb
+++ b/app/models/note_diff_file.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class NoteDiffFile < ActiveRecord::Base
+class NoteDiffFile < ApplicationRecord
include DiffFile
scope :for_commit_or_unresolved, -> do
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index e82eaf4e069..61af5c09ae4 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class NotificationSetting < ActiveRecord::Base
+class NotificationSetting < ApplicationRecord
include IgnorableColumn
ignore_column :events
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index 7a33ade826b..82901ceec01 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class PagesDomain < ActiveRecord::Base
+class PagesDomain < ApplicationRecord
VERIFICATION_KEY = 'gitlab-pages-verification-code'.freeze
VERIFICATION_THRESHOLD = 3.days.freeze
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index ed78a46eaf3..570112b63b7 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class PersonalAccessToken < ActiveRecord::Base
+class PersonalAccessToken < ApplicationRecord
include Expirable
include IgnorableColumn
include TokenAuthenticatable
diff --git a/app/models/pool_repository.rb b/app/models/pool_repository.rb
index 4635fc72dc7..35c718365b4 100644
--- a/app/models/pool_repository.rb
+++ b/app/models/pool_repository.rb
@@ -3,7 +3,7 @@
# The PoolRepository model is the database equivalent of an ObjectPool for Gitaly
# That is; PoolRepository is the record in the database, ObjectPool is the
# repository on disk
-class PoolRepository < ActiveRecord::Base
+class PoolRepository < ApplicationRecord
include Shardable
include AfterCommitQueue
diff --git a/app/models/postgresql/replication_slot.rb b/app/models/postgresql/replication_slot.rb
index e264fe88e47..74ccf23cf69 100644
--- a/app/models/postgresql/replication_slot.rb
+++ b/app/models/postgresql/replication_slot.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Postgresql
- class ReplicationSlot < ActiveRecord::Base
+ class ReplicationSlot < ApplicationRecord
self.table_name = 'pg_replication_slots'
# Returns true if there are any replication slots in use.
diff --git a/app/models/programming_language.rb b/app/models/programming_language.rb
index 5f0f313b7f9..375fbe9b5a9 100644
--- a/app/models/programming_language.rb
+++ b/app/models/programming_language.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProgrammingLanguage < ActiveRecord::Base
+class ProgrammingLanguage < ApplicationRecord
validates :name, presence: true
validates :color, allow_blank: false, color: true
diff --git a/app/models/project.rb b/app/models/project.rb
index 06010409574..82c2f9090c8 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2,7 +2,7 @@
require 'carrierwave/orm/activerecord'
-class Project < ActiveRecord::Base
+class Project < ApplicationRecord
include Gitlab::ConfigHelper
include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel
diff --git a/app/models/project_authorization.rb b/app/models/project_authorization.rb
index 2c590008db2..f95d3ab54e2 100644
--- a/app/models/project_authorization.rb
+++ b/app/models/project_authorization.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectAuthorization < ActiveRecord::Base
+class ProjectAuthorization < ApplicationRecord
include FromUnion
belongs_to :user
diff --git a/app/models/project_auto_devops.rb b/app/models/project_auto_devops.rb
index e353a6443c4..f972c40f317 100644
--- a/app/models/project_auto_devops.rb
+++ b/app/models/project_auto_devops.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectAutoDevops < ActiveRecord::Base
+class ProjectAutoDevops < ApplicationRecord
belongs_to :project
enum deploy_strategy: {
diff --git a/app/models/project_ci_cd_setting.rb b/app/models/project_ci_cd_setting.rb
index 1dad235cc2b..1414164b703 100644
--- a/app/models/project_ci_cd_setting.rb
+++ b/app/models/project_ci_cd_setting.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectCiCdSetting < ActiveRecord::Base
+class ProjectCiCdSetting < ApplicationRecord
belongs_to :project, inverse_of: :ci_cd_settings
# The version of the schema that first introduced this model/table.
diff --git a/app/models/project_custom_attribute.rb b/app/models/project_custom_attribute.rb
index 4e767cb3b26..b0da586988a 100644
--- a/app/models/project_custom_attribute.rb
+++ b/app/models/project_custom_attribute.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectCustomAttribute < ActiveRecord::Base
+class ProjectCustomAttribute < ApplicationRecord
belongs_to :project
validates :project, :key, :value, presence: true
diff --git a/app/models/project_daily_statistic.rb b/app/models/project_daily_statistic.rb
index ff115dd010f..5ee11ab186e 100644
--- a/app/models/project_daily_statistic.rb
+++ b/app/models/project_daily_statistic.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectDailyStatistic < ActiveRecord::Base
+class ProjectDailyStatistic < ApplicationRecord
belongs_to :project
scope :of_project, -> (project) { where(project: project) }
diff --git a/app/models/project_deploy_token.rb b/app/models/project_deploy_token.rb
index 719c492a1ff..a55667496fb 100644
--- a/app/models/project_deploy_token.rb
+++ b/app/models/project_deploy_token.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectDeployToken < ActiveRecord::Base
+class ProjectDeployToken < ApplicationRecord
belongs_to :project
belongs_to :deploy_token, inverse_of: :project_deploy_tokens
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index e6787236c4e..0542581c6e0 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectFeature < ActiveRecord::Base
+class ProjectFeature < ApplicationRecord
# == Project features permissions
#
# Grants access level to project tools
diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb
index bc3759142ae..58b555c3581 100644
--- a/app/models/project_group_link.rb
+++ b/app/models/project_group_link.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectGroupLink < ActiveRecord::Base
+class ProjectGroupLink < ApplicationRecord
include Expirable
GUEST = 10
diff --git a/app/models/project_import_data.rb b/app/models/project_import_data.rb
index aa0c121fe99..580e8dfd833 100644
--- a/app/models/project_import_data.rb
+++ b/app/models/project_import_data.rb
@@ -2,7 +2,7 @@
require 'carrierwave/orm/activerecord'
-class ProjectImportData < ActiveRecord::Base
+class ProjectImportData < ApplicationRecord
belongs_to :project, inverse_of: :import_data
attr_encrypted :credentials,
key: Settings.attr_encrypted_db_key_base,
diff --git a/app/models/project_import_state.rb b/app/models/project_import_state.rb
index 488f0cb5971..1605345efd5 100644
--- a/app/models/project_import_state.rb
+++ b/app/models/project_import_state.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectImportState < ActiveRecord::Base
+class ProjectImportState < ApplicationRecord
include AfterCommitQueue
self.table_name = "project_mirror_data"
diff --git a/app/models/project_repository.rb b/app/models/project_repository.rb
index 38913f3f2f5..092efabd73f 100644
--- a/app/models/project_repository.rb
+++ b/app/models/project_repository.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectRepository < ActiveRecord::Base
+class ProjectRepository < ApplicationRecord
include Shardable
belongs_to :project, inverse_of: :project_repository
diff --git a/app/models/project_statistics.rb b/app/models/project_statistics.rb
index 781a197d56f..c020e72908c 100644
--- a/app/models/project_statistics.rb
+++ b/app/models/project_statistics.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectStatistics < ActiveRecord::Base
+class ProjectStatistics < ApplicationRecord
belongs_to :project
belongs_to :namespace
diff --git a/app/models/prometheus_metric.rb b/app/models/prometheus_metric.rb
index 5594594a48d..62090444f79 100644
--- a/app/models/prometheus_metric.rb
+++ b/app/models/prometheus_metric.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class PrometheusMetric < ActiveRecord::Base
+class PrometheusMetric < ApplicationRecord
belongs_to :project, validate: true, inverse_of: :prometheus_metrics
enum group: {
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index 597431be65a..ee0c94c20af 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProtectedBranch < ActiveRecord::Base
+class ProtectedBranch < ApplicationRecord
include ProtectedRef
protected_ref_access_levels :merge, :push
diff --git a/app/models/protected_branch/merge_access_level.rb b/app/models/protected_branch/merge_access_level.rb
index b0d5c64e931..de240e40316 100644
--- a/app/models/protected_branch/merge_access_level.rb
+++ b/app/models/protected_branch/merge_access_level.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-class ProtectedBranch::MergeAccessLevel < ActiveRecord::Base
+class ProtectedBranch::MergeAccessLevel < ApplicationRecord
include ProtectedBranchAccess
end
diff --git a/app/models/protected_branch/push_access_level.rb b/app/models/protected_branch/push_access_level.rb
index b2a88229853..bde1d29ad7f 100644
--- a/app/models/protected_branch/push_access_level.rb
+++ b/app/models/protected_branch/push_access_level.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-class ProtectedBranch::PushAccessLevel < ActiveRecord::Base
+class ProtectedBranch::PushAccessLevel < ApplicationRecord
include ProtectedBranchAccess
end
diff --git a/app/models/protected_tag.rb b/app/models/protected_tag.rb
index d28ebabfe49..6b507429e57 100644
--- a/app/models/protected_tag.rb
+++ b/app/models/protected_tag.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProtectedTag < ActiveRecord::Base
+class ProtectedTag < ApplicationRecord
include ProtectedRef
validates :name, uniqueness: { scope: :project_id }
diff --git a/app/models/protected_tag/create_access_level.rb b/app/models/protected_tag/create_access_level.rb
index b06e55fb5dd..9fcfa7646a2 100644
--- a/app/models/protected_tag/create_access_level.rb
+++ b/app/models/protected_tag/create_access_level.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProtectedTag::CreateAccessLevel < ActiveRecord::Base
+class ProtectedTag::CreateAccessLevel < ApplicationRecord
include ProtectedTagAccess
def check_access(user)
diff --git a/app/models/push_event_payload.rb b/app/models/push_event_payload.rb
index c7769edf055..537859ec7b7 100644
--- a/app/models/push_event_payload.rb
+++ b/app/models/push_event_payload.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class PushEventPayload < ActiveRecord::Base
+class PushEventPayload < ApplicationRecord
include ShaAttribute
belongs_to :event, inverse_of: :push_event_payload
diff --git a/app/models/redirect_route.rb b/app/models/redirect_route.rb
index c6bd4bb6dfa..2e4769364c6 100644
--- a/app/models/redirect_route.rb
+++ b/app/models/redirect_route.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class RedirectRoute < ActiveRecord::Base
+class RedirectRoute < ApplicationRecord
belongs_to :source, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
validates :source, presence: true
diff --git a/app/models/release.rb b/app/models/release.rb
index 0dae5c90394..746fc31a038 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Release < ActiveRecord::Base
+class Release < ApplicationRecord
include CacheMarkdownField
include Gitlab::Utils::StrongMemoize
diff --git a/app/models/releases/link.rb b/app/models/releases/link.rb
index 6c507c47752..36ec33d3e3e 100644
--- a/app/models/releases/link.rb
+++ b/app/models/releases/link.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Releases
- class Link < ActiveRecord::Base
+ class Link < ApplicationRecord
self.table_name = 'release_links'
belongs_to :release
diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb
index 5eba7ddd75c..5610cfe0f24 100644
--- a/app/models/remote_mirror.rb
+++ b/app/models/remote_mirror.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class RemoteMirror < ActiveRecord::Base
+class RemoteMirror < ApplicationRecord
include AfterCommitQueue
include MirrorAuthentication
diff --git a/app/models/repository_language.rb b/app/models/repository_language.rb
index b18142a2ac4..e6867f905e2 100644
--- a/app/models/repository_language.rb
+++ b/app/models/repository_language.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class RepositoryLanguage < ActiveRecord::Base
+class RepositoryLanguage < ApplicationRecord
belongs_to :project
belongs_to :programming_language
diff --git a/app/models/resource_label_event.rb b/app/models/resource_label_event.rb
index 3fd96b9dc18..f2c7cb6a65d 100644
--- a/app/models/resource_label_event.rb
+++ b/app/models/resource_label_event.rb
@@ -2,7 +2,7 @@
# This model is not used yet, it will be used for:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/48483
-class ResourceLabelEvent < ActiveRecord::Base
+class ResourceLabelEvent < ApplicationRecord
include Importable
include Gitlab::Utils::StrongMemoize
include CacheMarkdownField
diff --git a/app/models/route.rb b/app/models/route.rb
index 4b23dfa5778..7e3db54d4fe 100644
--- a/app/models/route.rb
+++ b/app/models/route.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Route < ActiveRecord::Base
+class Route < ApplicationRecord
include CaseSensitivity
belongs_to :source, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb
index 6caab24143b..0427d5b9ca7 100644
--- a/app/models/sent_notification.rb
+++ b/app/models/sent_notification.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class SentNotification < ActiveRecord::Base
+class SentNotification < ApplicationRecord
serialize :position, Gitlab::Diff::Position # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :project
diff --git a/app/models/service.rb b/app/models/service.rb
index da523bfa426..c6d5eb353dc 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -2,7 +2,7 @@
# To add new service you should build a class inherited from Service
# and implement a set of methods
-class Service < ActiveRecord::Base
+class Service < ApplicationRecord
include Sortable
include Importable
include ProjectServicesLoggable
diff --git a/app/models/shard.rb b/app/models/shard.rb
index e39d4232486..335a279c6aa 100644
--- a/app/models/shard.rb
+++ b/app/models/shard.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Shard < ActiveRecord::Base
+class Shard < ApplicationRecord
# Store shard names from the configuration file in the database. This is not a
# list of active shards - we just want to assign an immutable, unique ID to
# every shard name for easy indexing / referencing.
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index f23ddd64fe3..f4fdac2558c 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Snippet < ActiveRecord::Base
+class Snippet < ApplicationRecord
include Gitlab::VisibilityLevel
include Redactable
include CacheMarkdownField
diff --git a/app/models/spam_log.rb b/app/models/spam_log.rb
index ef3f974b959..5b9ece8373f 100644
--- a/app/models/spam_log.rb
+++ b/app/models/spam_log.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class SpamLog < ActiveRecord::Base
+class SpamLog < ApplicationRecord
belongs_to :user
validates :user, presence: true
diff --git a/app/models/subscription.rb b/app/models/subscription.rb
index 0f6ee0ddf7e..24a2b8b5167 100644
--- a/app/models/subscription.rb
+++ b/app/models/subscription.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Subscription < ActiveRecord::Base
+class Subscription < ApplicationRecord
belongs_to :user
belongs_to :project
belongs_to :subscribable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb
index d555ebe5322..55da37c9545 100644
--- a/app/models/system_note_metadata.rb
+++ b/app/models/system_note_metadata.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class SystemNoteMetadata < ActiveRecord::Base
+class SystemNoteMetadata < ApplicationRecord
# These notes's action text might contain a reference that is external.
# We should always force a deep validation upon references that are found
# in this note type.
diff --git a/app/models/term_agreement.rb b/app/models/term_agreement.rb
index 9b3c8ac68bd..a4a9dc10282 100644
--- a/app/models/term_agreement.rb
+++ b/app/models/term_agreement.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class TermAgreement < ActiveRecord::Base
+class TermAgreement < ApplicationRecord
belongs_to :term, class_name: 'ApplicationSetting::Term'
belongs_to :user
diff --git a/app/models/timelog.rb b/app/models/timelog.rb
index e04c644a53a..048134fbf04 100644
--- a/app/models/timelog.rb
+++ b/app/models/timelog.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Timelog < ActiveRecord::Base
+class Timelog < ApplicationRecord
validates :time_spent, :user, presence: true
validate :issuable_id_is_present
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 2b0dee875a3..5dcc3e9945a 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Todo < ActiveRecord::Base
+class Todo < ApplicationRecord
include Sortable
include FromUnion
diff --git a/app/models/trending_project.rb b/app/models/trending_project.rb
index 7b22e8cb760..810dee672b2 100644
--- a/app/models/trending_project.rb
+++ b/app/models/trending_project.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class TrendingProject < ActiveRecord::Base
+class TrendingProject < ApplicationRecord
belongs_to :project
# The number of months to include in the trending calculation.
diff --git a/app/models/u2f_registration.rb b/app/models/u2f_registration.rb
index 37598173fd1..b4645462314 100644
--- a/app/models/u2f_registration.rb
+++ b/app/models/u2f_registration.rb
@@ -2,7 +2,7 @@
# Registration information for U2F (universal 2nd factor) devices, like Yubikeys
-class U2fRegistration < ActiveRecord::Base
+class U2fRegistration < ApplicationRecord
belongs_to :user
def self.register(user, app_id, params, challenges)
diff --git a/app/models/upload.rb b/app/models/upload.rb
index 20860f14b83..9bffdcdb2e7 100644
--- a/app/models/upload.rb
+++ b/app/models/upload.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class Upload < ActiveRecord::Base
+class Upload < ApplicationRecord
# Upper limit for foreground checksum processing
CHECKSUM_THRESHOLD = 100.megabytes
diff --git a/app/models/user.rb b/app/models/user.rb
index d2be26370ff..e0c518a9b75 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -432,7 +432,7 @@ class User < ApplicationRecord
fuzzy_arel_match(:name, query, lower_exact_match: true)
.or(fuzzy_arel_match(:username, query, lower_exact_match: true))
.or(arel_table[:email].eq(query))
- ).reorder(order % { query: ActiveRecord::Base.connection.quote(query) }, :name)
+ ).reorder(order % { query: ApplicationRecord.connection.quote(query) }, :name)
end
# Limits the result set to users _not_ in the given query/list of IDs.
diff --git a/app/models/user_agent_detail.rb b/app/models/user_agent_detail.rb
index e2b2e7f1df9..fea1fce3c8d 100644
--- a/app/models/user_agent_detail.rb
+++ b/app/models/user_agent_detail.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UserAgentDetail < ActiveRecord::Base
+class UserAgentDetail < ApplicationRecord
belongs_to :subject, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
validates :user_agent, :ip_address, :subject_id, :subject_type, presence: true
diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb
index 76e7bc06b4e..027ee44c6a9 100644
--- a/app/models/user_callout.rb
+++ b/app/models/user_callout.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UserCallout < ActiveRecord::Base
+class UserCallout < ApplicationRecord
belongs_to :user
# We use `UserCalloutEnums.feature_names` here so that EE can more easily
diff --git a/app/models/user_custom_attribute.rb b/app/models/user_custom_attribute.rb
index e0ffe8ebbfd..727975c3f6e 100644
--- a/app/models/user_custom_attribute.rb
+++ b/app/models/user_custom_attribute.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UserCustomAttribute < ActiveRecord::Base
+class UserCustomAttribute < ApplicationRecord
belongs_to :user
validates :user_id, :key, :value, presence: true
diff --git a/app/models/user_interacted_project.rb b/app/models/user_interacted_project.rb
index 5fc59b274f5..f6f72f4b77a 100644
--- a/app/models/user_interacted_project.rb
+++ b/app/models/user_interacted_project.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UserInteractedProject < ActiveRecord::Base
+class UserInteractedProject < ApplicationRecord
belongs_to :user
belongs_to :project
diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb
index 32d0407800f..282b192167f 100644
--- a/app/models/user_preference.rb
+++ b/app/models/user_preference.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UserPreference < ActiveRecord::Base
+class UserPreference < ApplicationRecord
# We could use enums, but Rails 4 doesn't support multiple
# enum options with same name for multiple fields, also it creates
# extra methods that aren't really needed here.
diff --git a/app/models/user_status.rb b/app/models/user_status.rb
index 2bbb0c59ac1..6ced4f56823 100644
--- a/app/models/user_status.rb
+++ b/app/models/user_status.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UserStatus < ActiveRecord::Base
+class UserStatus < ApplicationRecord
include CacheMarkdownField
self.primary_key = :user_id
diff --git a/app/models/user_synced_attributes_metadata.rb b/app/models/user_synced_attributes_metadata.rb
index 7115262942d..5aacf11b1cb 100644
--- a/app/models/user_synced_attributes_metadata.rb
+++ b/app/models/user_synced_attributes_metadata.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UserSyncedAttributesMetadata < ActiveRecord::Base
+class UserSyncedAttributesMetadata < ApplicationRecord
belongs_to :user
validates :user, presence: true
diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb
index bdaf58ae1c1..9be6bd2e6f3 100644
--- a/app/models/users_star_project.rb
+++ b/app/models/users_star_project.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UsersStarProject < ActiveRecord::Base
+class UsersStarProject < ApplicationRecord
belongs_to :project, counter_cache: :star_count, touch: true
belongs_to :user
diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb
index 29656b17183..ed3daf6585b 100644
--- a/app/presenters/ci/build_runner_presenter.rb
+++ b/app/presenters/ci/build_runner_presenter.rb
@@ -4,6 +4,7 @@ module Ci
class BuildRunnerPresenter < SimpleDelegator
include Gitlab::Utils::StrongMemoize
+ DEFAULT_GIT_DEPTH_MERGE_REQUEST = 10
RUNNER_REMOTE_TAG_PREFIX = 'refs/tags/'.freeze
RUNNER_REMOTE_BRANCH_PREFIX = 'refs/remotes/origin/'.freeze
@@ -27,6 +28,7 @@ module Ci
def git_depth
strong_memoize(:git_depth) do
git_depth = variables&.find { |variable| variable[:key] == 'GIT_DEPTH' }&.dig(:value)
+ git_depth ||= DEFAULT_GIT_DEPTH_MERGE_REQUEST if merge_request_ref?
git_depth.to_i
end
end
@@ -35,8 +37,9 @@ module Ci
specs = []
if git_depth > 0
- specs << refspec_for_branch(ref) if branch? || merge_request_event?
+ specs << refspec_for_branch(ref) if branch? || legacy_detached_merge_request_pipeline?
specs << refspec_for_tag(ref) if tag?
+ specs << refspec_for_merge_request_ref if merge_request_ref?
else
specs << refspec_for_branch
specs << refspec_for_tag
@@ -83,5 +86,9 @@ module Ci
def refspec_for_tag(ref = '*')
"+#{Gitlab::Git::TAG_REF_PREFIX}#{ref}:#{RUNNER_REMOTE_TAG_PREFIX}#{ref}"
end
+
+ def refspec_for_merge_request_ref
+ "+#{ref}:#{ref}"
+ end
end
end
diff --git a/app/presenters/clusters/cluster_presenter.rb b/app/presenters/clusters/cluster_presenter.rb
index 7a5b68f9a4b..81994bbce7d 100644
--- a/app/presenters/clusters/cluster_presenter.rb
+++ b/app/presenters/clusters/cluster_presenter.rb
@@ -48,6 +48,10 @@ module Clusters
end
end
+ def read_only_kubernetes_platform_fields?
+ !cluster.provided_by_user?
+ end
+
private
def clusterable
diff --git a/app/services/clusters/applications/base_service.rb b/app/services/clusters/applications/base_service.rb
index cbd1cf03ae1..14a45437287 100644
--- a/app/services/clusters/applications/base_service.rb
+++ b/app/services/clusters/applications/base_service.rb
@@ -41,7 +41,7 @@ module Clusters
raise NotImplementedError
end
- def builders
+ def builder
raise NotImplementedError
end
@@ -50,11 +50,27 @@ module Clusters
end
def instantiate_application
- builder.call(@cluster) || raise(InvalidApplicationError, "invalid application: #{application_name}")
+ raise_invalid_application_error if invalid_application?
+
+ builder || raise(InvalidApplicationError, "invalid application: #{application_name}")
end
- def builder
- builders[application_name] || raise(InvalidApplicationError, "invalid application: #{application_name}")
+ def raise_invalid_application_error
+ raise(InvalidApplicationError, "invalid application: #{application_name}")
+ end
+
+ def invalid_application?
+ unknown_application? || (!cluster.project_type? && project_only_application?)
+ end
+
+ def unknown_application?
+ Clusters::Cluster::APPLICATIONS.keys.exclude?(application_name)
+ end
+
+ # These applications will need extra configuration to enable them to work
+ # with groups of projects
+ def project_only_application?
+ Clusters::Cluster::PROJECT_ONLY_APPLICATIONS.include?(application_name)
end
def application_name
diff --git a/app/services/clusters/applications/create_service.rb b/app/services/clusters/applications/create_service.rb
index c6f729aaa8a..ae36da7b3dd 100644
--- a/app/services/clusters/applications/create_service.rb
+++ b/app/services/clusters/applications/create_service.rb
@@ -9,25 +9,9 @@ module Clusters
application.updateable? ? ClusterUpgradeAppWorker : ClusterInstallAppWorker
end
- def builders
- {
- "helm" => -> (cluster) { cluster.application_helm || cluster.build_application_helm },
- "ingress" => -> (cluster) { cluster.application_ingress || cluster.build_application_ingress },
- "cert_manager" => -> (cluster) { cluster.application_cert_manager || cluster.build_application_cert_manager },
- "runner" => -> (cluster) { cluster.application_runner || cluster.build_application_runner }
- }.tap do |hash|
- hash.merge!(project_builders) if cluster.project_type?
- end
- end
-
- # These applications will need extra configuration to enable them to work
- # with groups of projects
- def project_builders
- {
- "prometheus" => -> (cluster) { cluster.application_prometheus || cluster.build_application_prometheus },
- "jupyter" => -> (cluster) { cluster.application_jupyter || cluster.build_application_jupyter },
- "knative" => -> (cluster) { cluster.application_knative || cluster.build_application_knative }
- }
+ def builder
+ cluster.method("application_#{application_name}").call ||
+ cluster.method("build_application_#{application_name}").call
end
end
end
diff --git a/app/services/clusters/applications/update_service.rb b/app/services/clusters/applications/update_service.rb
index a9d4e609992..5071c31839c 100644
--- a/app/services/clusters/applications/update_service.rb
+++ b/app/services/clusters/applications/update_service.rb
@@ -9,25 +9,8 @@ module Clusters
ClusterPatchAppWorker
end
- def builders
- {
- "helm" => -> (cluster) { cluster.application_helm },
- "ingress" => -> (cluster) { cluster.application_ingress },
- "cert_manager" => -> (cluster) { cluster.application_cert_manager }
- }.tap do |hash|
- hash.merge!(project_builders) if cluster.project_type?
- end
- end
-
- # These applications will need extra configuration to enable them to work
- # with groups of projects
- def project_builders
- {
- "prometheus" => -> (cluster) { cluster.application_prometheus },
- "runner" => -> (cluster) { cluster.application_runner },
- "jupyter" => -> (cluster) { cluster.application_jupyter },
- "knative" => -> (cluster) { cluster.application_knative }
- }
+ def builder
+ cluster.method("application_#{application_name}").call
end
end
end
diff --git a/app/services/error_tracking/list_issues_service.rb b/app/services/error_tracking/list_issues_service.rb
index a6c6bec9598..86ab21fa865 100644
--- a/app/services/error_tracking/list_issues_service.rb
+++ b/app/services/error_tracking/list_issues_service.rb
@@ -18,7 +18,7 @@ module ErrorTracking
end
if result[:error].present?
- return error(result[:error], :bad_request)
+ return error(result[:error], http_status_from_error_type(result[:error_type]))
end
success(issues: result[:issues])
@@ -30,6 +30,15 @@ module ErrorTracking
private
+ def http_status_from_error_type(error_type)
+ case error_type
+ when ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_MISSING_KEYS
+ :internal_server_error
+ else
+ :bad_request
+ end
+ end
+
def project_error_tracking_setting
project.error_tracking_setting
end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index f35ad2a9d8b..95bd83bb03c 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -76,13 +76,11 @@ class IssuableBaseService < BaseService
find_or_create_label_ids
end
- # rubocop: disable CodeReuse/ActiveRecord
def filter_labels_in_param(key)
return if params[key].to_a.empty?
- params[key] = available_labels.where(id: params[key]).pluck(:id)
+ params[key] = available_labels.id_in(params[key]).pluck_primary_key
end
- # rubocop: enable CodeReuse/ActiveRecord
def find_or_create_label_ids
labels = params.delete(:labels)
@@ -115,7 +113,7 @@ class IssuableBaseService < BaseService
new_label_ids -= remove_label_ids if remove_label_ids
end
- new_label_ids
+ new_label_ids.uniq
end
def available_labels
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 11ede5223e5..3e208241da5 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -54,7 +54,7 @@ module MergeRequests
merge_request, merge_request.project, current_user, merge_request.assignee)
end
- def create_merge_request_pipeline(merge_request, user)
+ def create_pipeline_for(merge_request, user)
return unless Feature.enabled?(:ci_merge_request_pipeline,
merge_request.source_project,
default_enabled: true)
@@ -65,12 +65,24 @@ module MergeRequests
return if merge_request.merge_request_pipeline_exists?
return if merge_request.has_no_commits?
- Ci::CreatePipelineService
- .new(merge_request.source_project, user, ref: merge_request.source_branch)
- .execute(:merge_request_event,
- ignore_skip_ci: true,
- save_on_errors: false,
- merge_request: merge_request)
+ create_detached_merge_request_pipeline(merge_request, user)
+ end
+
+ def create_detached_merge_request_pipeline(merge_request, user)
+ if can_use_merge_request_ref?(merge_request)
+ Ci::CreatePipelineService.new(merge_request.source_project, user,
+ ref: merge_request.ref_path)
+ .execute(:merge_request_event, merge_request: merge_request)
+ else
+ Ci::CreatePipelineService.new(merge_request.source_project, user,
+ ref: merge_request.source_branch)
+ .execute(:merge_request_event, merge_request: merge_request)
+ end
+ end
+
+ def can_use_merge_request_ref?(merge_request)
+ Feature.enabled?(:ci_use_merge_request_ref, project, default_enabled: true) &&
+ !merge_request.for_fork?
end
# Returns all origin and fork merge requests from `@project` satisfying passed arguments.
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 02c2388c05c..06e46595b95 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -25,7 +25,7 @@ module MergeRequests
def after_create(issuable)
todo_service.new_merge_request(issuable, current_user)
issuable.cache_merge_request_closes_issues!(current_user)
- create_merge_request_pipeline(issuable, current_user)
+ create_pipeline_for(issuable, current_user)
issuable.update_head_pipeline
super
diff --git a/app/services/merge_requests/delete_non_latest_diffs_service.rb b/app/services/merge_requests/delete_non_latest_diffs_service.rb
index d5929446122..bdb7ec8a7c2 100644
--- a/app/services/merge_requests/delete_non_latest_diffs_service.rb
+++ b/app/services/merge_requests/delete_non_latest_diffs_service.rb
@@ -8,15 +8,13 @@ module MergeRequests
@merge_request = merge_request
end
- # rubocop: disable CodeReuse/ActiveRecord
def execute
diffs = @merge_request.non_latest_diffs.with_files
diffs.each_batch(of: BATCH_SIZE) do |relation, index|
- ids = relation.pluck(:id).map { |id| [id] }
+ ids = relation.pluck_primary_key.map { |id| [id] }
DeleteDiffFilesWorker.bulk_perform_in(index * 5.minutes, ids)
end
end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb
index 69cc441f1bb..87147d90c32 100644
--- a/app/services/merge_requests/merge_to_ref_service.rb
+++ b/app/services/merge_requests/merge_to_ref_service.rb
@@ -41,9 +41,7 @@ module MergeRequests
super
error =
- if Feature.disabled?(:merge_to_tmp_merge_ref_path, project)
- 'Feature is not enabled'
- elsif !hooks_validation_pass?(merge_request)
+ if !hooks_validation_pass?(merge_request)
hooks_validation_error(merge_request)
elsif !@merge_request.mergeable_to_ref?
"Merge request is not mergeable to #{target_ref}"
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index f5dc5a0256d..51d27673787 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -107,7 +107,7 @@ module MergeRequests
end
merge_request.mark_as_unchecked
- create_merge_request_pipeline(merge_request, current_user)
+ create_pipeline_for(merge_request, current_user)
UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id)
end
diff --git a/app/services/milestones/promote_service.rb b/app/services/milestones/promote_service.rb
index cbe5996e8ca..f6c04a7bae2 100644
--- a/app/services/milestones/promote_service.rb
+++ b/app/services/milestones/promote_service.rb
@@ -26,17 +26,15 @@ module Milestones
private
- # rubocop: disable CodeReuse/ActiveRecord
def milestone_ids_for_merge(group_milestone)
# Pluck need to be used here instead of select so the array of ids
# is persistent after old milestones gets deleted.
@milestone_ids_for_merge ||= begin
search_params = { title: group_milestone.title, project_ids: group_project_ids, state: 'all' }
milestones = MilestonesFinder.new(search_params).execute
- milestones.pluck(:id)
+ milestones.pluck_primary_key
end
end
- # rubocop: enable CodeReuse/ActiveRecord
def move_children_to_group_milestone(group_milestone)
milestone_ids_for_merge(group_milestone).in_groups_of(100, false) do |milestone_ids|
diff --git a/app/services/projects/after_import_service.rb b/app/services/projects/after_import_service.rb
index bbdde4408d2..afb9048e87b 100644
--- a/app/services/projects/after_import_service.rb
+++ b/app/services/projects/after_import_service.rb
@@ -9,7 +9,7 @@ module Projects
end
def execute
- Projects::HousekeepingService.new(@project).execute do
+ Projects::HousekeepingService.new(@project, :gc).execute do
repository.delete_all_refs_except(RESERVED_REF_PREFIXES)
end
rescue Projects::HousekeepingService::LeaseTaken => e
diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb
index 2f6dc4207dd..10bd5363b51 100644
--- a/app/services/projects/housekeeping_service.rb
+++ b/app/services/projects/housekeeping_service.rb
@@ -18,8 +18,9 @@ module Projects
end
end
- def initialize(project)
+ def initialize(project, task = nil)
@project = project
+ @task = task
end
def execute
@@ -69,6 +70,8 @@ module Projects
end
def task
+ return @task if @task
+
if pushes_since_gc % gc_period == 0
:gc
elsif pushes_since_gc % full_repack_period == 0
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 131efb8925e..f463e08ee7e 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -4,21 +4,24 @@ module QuickActions
class InterpretService < BaseService
include Gitlab::Utils::StrongMemoize
include Gitlab::QuickActions::Dsl
+ include Gitlab::QuickActions::IssueActions
+ include Gitlab::QuickActions::IssueAndMergeRequestActions
+ include Gitlab::QuickActions::IssuableActions
+ include Gitlab::QuickActions::MergeRequestActions
+ include Gitlab::QuickActions::CommitActions
+ include Gitlab::QuickActions::CommonActions
- attr_reader :issuable
+ attr_reader :quick_action_target
# Counts how many commands have been executed.
# Used to display relevant feedback on UI when a note
# with only commands has been processed.
attr_accessor :commands_executed_count
- SHRUG = '¯\\_(ツ)_/¯'.freeze
- TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
-
- # Takes an issuable and returns an array of all the available commands
+ # Takes an quick_action_target and returns an array of all the available commands
# represented with .to_h
- def available_commands(issuable)
- @issuable = issuable
+ def available_commands(quick_action_target)
+ @quick_action_target = quick_action_target
self.class.command_definitions.map do |definition|
next unless definition.available?(self)
@@ -29,10 +32,10 @@ module QuickActions
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record.
- def execute(content, issuable, only: nil)
+ def execute(content, quick_action_target, only: nil)
return [content, {}] unless current_user.can?(:use_quick_actions)
- @issuable = issuable
+ @quick_action_target = quick_action_target
@updates = {}
content, commands = extractor.extract_commands(content, only: only)
@@ -43,10 +46,10 @@ module QuickActions
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and array of changes explained.
- def explain(content, issuable)
+ def explain(content, quick_action_target)
return [content, []] unless current_user.can?(:use_quick_actions)
- @issuable = issuable
+ @quick_action_target = quick_action_target
content, commands = extractor.extract_commands(content)
commands = explain_commands(commands)
@@ -59,598 +62,6 @@ module QuickActions
Gitlab::QuickActions::Extractor.new(self.class.command_definitions)
end
- desc do
- "Close this #{issuable.to_ability_name.humanize(capitalize: false)}"
- end
- explanation do
- "Closes this #{issuable.to_ability_name.humanize(capitalize: false)}."
- end
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- issuable.open? &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
- end
- command :close do
- @updates[:state_event] = 'close'
- end
-
- desc do
- "Reopen this #{issuable.to_ability_name.humanize(capitalize: false)}"
- end
- explanation do
- "Reopens this #{issuable.to_ability_name.humanize(capitalize: false)}."
- end
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- issuable.closed? &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
- end
- command :reopen do
- @updates[:state_event] = 'reopen'
- end
-
- desc 'Merge (when the pipeline succeeds)'
- explanation 'Merges this merge request when the pipeline succeeds.'
- condition do
- last_diff_sha = params && params[:merge_request_diff_head_sha]
- issuable.is_a?(MergeRequest) &&
- issuable.persisted? &&
- issuable.mergeable_with_quick_action?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha)
- end
- command :merge do
- @updates[:merge] = params[:merge_request_diff_head_sha]
- end
-
- desc 'Change title'
- explanation do |title_param|
- "Changes the title to \"#{title_param}\"."
- end
- params '<New title>'
- condition do
- issuable.persisted? &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
- end
- command :title do |title_param|
- @updates[:title] = title_param
- end
-
- desc 'Assign'
- # rubocop: disable CodeReuse/ActiveRecord
- explanation do |users|
- users = issuable.allows_multiple_assignees? ? users : users.take(1)
- "Assigns #{users.map(&:to_reference).to_sentence}."
- end
- # rubocop: enable CodeReuse/ActiveRecord
- params do
- issuable.allows_multiple_assignees? ? '@user1 @user2' : '@user'
- end
- condition do
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- parse_params do |assignee_param|
- extract_users(assignee_param)
- end
- command :assign do |users|
- next if users.empty?
-
- if issuable.allows_multiple_assignees?
- @updates[:assignee_ids] ||= issuable.assignees.map(&:id)
- @updates[:assignee_ids] += users.map(&:id)
- else
- @updates[:assignee_ids] = [users.first.id]
- end
- end
-
- desc do
- if issuable.allows_multiple_assignees?
- 'Remove all or specific assignee(s)'
- else
- 'Remove assignee'
- end
- end
- explanation do |users = nil|
- assignees = issuable.assignees
- assignees &= users if users.present? && issuable.allows_multiple_assignees?
- "Removes #{'assignee'.pluralize(assignees.size)} #{assignees.map(&:to_reference).to_sentence}."
- end
- params do
- issuable.allows_multiple_assignees? ? '@user1 @user2' : ''
- end
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- issuable.assignees.any? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- parse_params do |unassign_param|
- # When multiple users are assigned, all will be unassigned if multiple assignees are no longer allowed
- extract_users(unassign_param) if issuable.allows_multiple_assignees?
- end
- command :unassign do |users = nil|
- if issuable.allows_multiple_assignees? && users&.any?
- @updates[:assignee_ids] ||= issuable.assignees.map(&:id)
- @updates[:assignee_ids] -= users.map(&:id)
- else
- @updates[:assignee_ids] = []
- end
- end
-
- desc 'Set milestone'
- explanation do |milestone|
- "Sets the milestone to #{milestone.to_reference}." if milestone
- end
- params '%"milestone"'
- condition do
- current_user.can?(:"admin_#{issuable.to_ability_name}", project) &&
- find_milestones(project, state: 'active').any?
- end
- parse_params do |milestone_param|
- extract_references(milestone_param, :milestone).first ||
- find_milestones(project, title: milestone_param.strip).first
- end
- command :milestone do |milestone|
- @updates[:milestone_id] = milestone.id if milestone
- end
-
- desc 'Remove milestone'
- explanation do
- "Removes #{issuable.milestone.to_reference(format: :name)} milestone."
- end
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- issuable.milestone_id? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- command :remove_milestone do
- @updates[:milestone_id] = nil
- end
-
- desc 'Add label(s)'
- explanation do |labels_param|
- labels = find_label_references(labels_param)
-
- "Adds #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any?
- end
- params '~label1 ~"label 2"'
- condition do
- parent &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", parent) &&
- find_labels.any?
- end
- command :label do |labels_param|
- label_ids = find_label_ids(labels_param)
-
- if label_ids.any?
- @updates[:add_label_ids] ||= []
- @updates[:add_label_ids] += label_ids
-
- @updates[:add_label_ids].uniq!
- end
- end
-
- desc 'Remove all or specific label(s)'
- explanation do |labels_param = nil|
- if labels_param.present?
- labels = find_label_references(labels_param)
- "Removes #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any?
- else
- 'Removes all labels.'
- end
- end
- params '~label1 ~"label 2"'
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- issuable.labels.any? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", parent)
- end
- command :unlabel do |labels_param = nil|
- if labels_param.present?
- label_ids = find_label_ids(labels_param)
-
- if label_ids.any?
- @updates[:remove_label_ids] ||= []
- @updates[:remove_label_ids] += label_ids
-
- @updates[:remove_label_ids].uniq!
- end
- else
- @updates[:label_ids] = []
- end
- end
-
- desc 'Replace all label(s)'
- explanation do |labels_param|
- labels = find_label_references(labels_param)
- "Replaces all labels with #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any?
- end
- params '~label1 ~"label 2"'
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- issuable.labels.any? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- command :relabel do |labels_param|
- label_ids = find_label_ids(labels_param)
-
- if label_ids.any?
- @updates[:label_ids] ||= []
- @updates[:label_ids] += label_ids
-
- @updates[:label_ids].uniq!
- end
- end
-
- desc 'Copy labels and milestone from other issue or merge request'
- explanation do |source_issuable|
- "Copy labels and milestone from #{source_issuable.to_reference}."
- end
- params '#issue | !merge_request'
- condition do
- [MergeRequest, Issue].include?(issuable.class) &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
- end
- parse_params do |issuable_param|
- extract_references(issuable_param, :issue).first ||
- extract_references(issuable_param, :merge_request).first
- end
- command :copy_metadata do |source_issuable|
- if source_issuable.present? && source_issuable.project.id == issuable.project.id
- @updates[:add_label_ids] = source_issuable.labels.map(&:id)
- @updates[:milestone_id] = source_issuable.milestone.id if source_issuable.milestone
- end
- end
-
- desc 'Add a todo'
- explanation 'Adds a todo.'
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- !TodoService.new.todo_exist?(issuable, current_user)
- end
- command :todo do
- @updates[:todo_event] = 'add'
- end
-
- desc 'Mark todo as done'
- explanation 'Marks todo as done.'
- condition do
- issuable.persisted? &&
- TodoService.new.todo_exist?(issuable, current_user)
- end
- command :done do
- @updates[:todo_event] = 'done'
- end
-
- desc 'Subscribe'
- explanation do
- "Subscribes to this #{issuable.to_ability_name.humanize(capitalize: false)}."
- end
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- !issuable.subscribed?(current_user, project)
- end
- command :subscribe do
- @updates[:subscription_event] = 'subscribe'
- end
-
- desc 'Unsubscribe'
- explanation do
- "Unsubscribes from this #{issuable.to_ability_name.humanize(capitalize: false)}."
- end
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted? &&
- issuable.subscribed?(current_user, project)
- end
- command :unsubscribe do
- @updates[:subscription_event] = 'unsubscribe'
- end
-
- desc 'Set due date'
- explanation do |due_date|
- "Sets the due date to #{due_date.to_s(:medium)}." if due_date
- end
- params '<in 2 days | this Friday | December 31st>'
- condition do
- issuable.respond_to?(:due_date) &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- parse_params do |due_date_param|
- Chronic.parse(due_date_param).try(:to_date)
- end
- command :due do |due_date|
- @updates[:due_date] = due_date if due_date
- end
-
- desc 'Remove due date'
- explanation 'Removes the due date.'
- condition do
- issuable.persisted? &&
- issuable.respond_to?(:due_date) &&
- issuable.due_date? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- command :remove_due_date do
- @updates[:due_date] = nil
- end
-
- desc 'Toggle the Work In Progress status'
- explanation do
- verb = issuable.work_in_progress? ? 'Unmarks' : 'Marks'
- noun = issuable.to_ability_name.humanize(capitalize: false)
- "#{verb} this #{noun} as Work In Progress."
- end
- condition do
- issuable.respond_to?(:work_in_progress?) &&
- # Allow it to mark as WIP on MR creation page _or_ through MR notes.
- (issuable.new_record? || current_user.can?(:"update_#{issuable.to_ability_name}", issuable))
- end
- command :wip do
- @updates[:wip_event] = issuable.work_in_progress? ? 'unwip' : 'wip'
- end
-
- desc 'Toggle emoji award'
- explanation do |name|
- "Toggles :#{name}: emoji award." if name
- end
- params ':emoji:'
- condition do
- issuable.is_a?(Issuable) &&
- issuable.persisted?
- end
- parse_params do |emoji_param|
- match = emoji_param.match(Banzai::Filter::EmojiFilter.emoji_pattern)
- match[1] if match
- end
- command :award do |name|
- if name && issuable.user_can_award?(current_user)
- @updates[:emoji_award] = name
- end
- end
-
- desc 'Set time estimate'
- explanation do |time_estimate|
- time_estimate = Gitlab::TimeTrackingFormatter.output(time_estimate)
-
- "Sets time estimate to #{time_estimate}." if time_estimate
- end
- params '<1w 3d 2h 14m>'
- condition do
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- parse_params do |raw_duration|
- Gitlab::TimeTrackingFormatter.parse(raw_duration)
- end
- command :estimate do |time_estimate|
- if time_estimate
- @updates[:time_estimate] = time_estimate
- end
- end
-
- desc 'Add or subtract spent time'
- explanation do |time_spent, time_spent_date|
- if time_spent
- if time_spent > 0
- verb = 'Adds'
- value = time_spent
- else
- verb = 'Subtracts'
- value = -time_spent
- end
-
- "#{verb} #{Gitlab::TimeTrackingFormatter.output(value)} spent time."
- end
- end
- params '<time(1h30m | -1h30m)> <date(YYYY-MM-DD)>'
- condition do
- issuable.is_a?(TimeTrackable) &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", issuable)
- end
- parse_params do |raw_time_date|
- Gitlab::QuickActions::SpendTimeAndDateSeparator.new(raw_time_date).execute
- end
- command :spend do |time_spent, time_spent_date|
- if time_spent
- @updates[:spend_time] = {
- duration: time_spent,
- user_id: current_user.id,
- spent_at: time_spent_date
- }
- end
- end
-
- desc 'Remove time estimate'
- explanation 'Removes time estimate.'
- condition do
- issuable.persisted? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- command :remove_estimate do
- @updates[:time_estimate] = 0
- end
-
- desc 'Remove spent time'
- explanation 'Removes spent time.'
- condition do
- issuable.persisted? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- command :remove_time_spent do
- @updates[:spend_time] = { duration: :reset, user_id: current_user.id }
- end
-
- desc "Append the comment with #{SHRUG}"
- params '<Comment>'
- substitution :shrug do |comment|
- "#{comment} #{SHRUG}"
- end
-
- desc "Append the comment with #{TABLEFLIP}"
- params '<Comment>'
- substitution :tableflip do |comment|
- "#{comment} #{TABLEFLIP}"
- end
-
- desc "Lock the discussion"
- explanation "Locks the discussion"
- condition do
- [MergeRequest, Issue].include?(issuable.class) &&
- issuable.persisted? &&
- !issuable.discussion_locked? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", issuable)
- end
- command :lock do
- @updates[:discussion_locked] = true
- end
-
- desc "Unlock the discussion"
- explanation "Unlocks the discussion"
- condition do
- [MergeRequest, Issue].include?(issuable.class) &&
- issuable.persisted? &&
- issuable.discussion_locked? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", issuable)
- end
- command :unlock do
- @updates[:discussion_locked] = false
- end
-
- # This is a dummy command, so that it appears in the autocomplete commands
- desc 'CC'
- params '@user'
- command :cc
-
- desc 'Set target branch'
- explanation do |branch_name|
- "Sets target branch to #{branch_name}."
- end
- params '<Local branch name>'
- condition do
- issuable.respond_to?(:target_branch) &&
- (current_user.can?(:"update_#{issuable.to_ability_name}", issuable) ||
- issuable.new_record?)
- end
- parse_params do |target_branch_param|
- target_branch_param.strip
- end
- command :target_branch do |branch_name|
- @updates[:target_branch] = branch_name if project.repository.branch_exists?(branch_name)
- end
-
- desc 'Move issue from one column of the board to another'
- explanation do |target_list_name|
- label = find_label_references(target_list_name).first
- "Moves issue to #{label} column in the board." if label
- end
- params '~"Target column"'
- condition do
- issuable.is_a?(Issue) &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable) &&
- issuable.project.boards.count == 1
- end
- # rubocop: disable CodeReuse/ActiveRecord
- command :board_move do |target_list_name|
- label_ids = find_label_ids(target_list_name)
-
- if label_ids.size == 1
- label_id = label_ids.first
-
- # Ensure this label corresponds to a list on the board
- next unless Label.on_project_boards(issuable.project_id).where(id: label_id).exists?
-
- @updates[:remove_label_ids] =
- issuable.labels.on_project_boards(issuable.project_id).where.not(id: label_id).pluck(:id)
- @updates[:add_label_ids] = [label_id]
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- desc 'Mark this issue as a duplicate of another issue'
- explanation do |duplicate_reference|
- "Marks this issue as a duplicate of #{duplicate_reference}."
- end
- params '#issue'
- condition do
- issuable.is_a?(Issue) &&
- issuable.persisted? &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
- end
- command :duplicate do |duplicate_param|
- canonical_issue = extract_references(duplicate_param, :issue).first
-
- if canonical_issue.present?
- @updates[:canonical_issue_id] = canonical_issue.id
- end
- end
-
- desc 'Move this issue to another project.'
- explanation do |path_to_project|
- "Moves this issue to #{path_to_project}."
- end
- params 'path/to/project'
- condition do
- issuable.is_a?(Issue) &&
- issuable.persisted? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
- end
- command :move do |target_project_path|
- target_project = Project.find_by_full_path(target_project_path)
-
- if target_project.present?
- @updates[:target_project] = target_project
- end
- end
-
- desc 'Make issue confidential.'
- explanation do
- 'Makes this issue confidential'
- end
- condition do
- issuable.is_a?(Issue) && current_user.can?(:"admin_#{issuable.to_ability_name}", issuable)
- end
- command :confidential do
- @updates[:confidential] = true
- end
-
- desc 'Tag this commit.'
- explanation do |tag_name, message|
- with_message = %{ with "#{message}"} if message.present?
- "Tags this commit to #{tag_name}#{with_message}."
- end
- params 'v1.2.3 <message>'
- parse_params do |tag_name_and_message|
- tag_name_and_message.split(' ', 2)
- end
- condition do
- issuable.is_a?(Commit) && current_user.can?(:push_code, project)
- end
- command :tag do |tag_name, message|
- @updates[:tag_name] = tag_name
- @updates[:tag_message] = message
- end
-
- desc 'Create a merge request.'
- explanation do |branch_name = nil|
- branch_text = branch_name ? "branch '#{branch_name}'" : 'a branch'
- "Creates #{branch_text} and a merge request to resolve this issue"
- end
- params "<branch name>"
- condition do
- issuable.is_a?(Issue) && current_user.can?(:create_merge_request_in, project) && current_user.can?(:push_code, project)
- end
- command :create_merge_request do |branch_name = nil|
- @updates[:create_merge_request] = {
- branch_name: branch_name,
- issue_iid: issuable.iid
- }
- end
-
# rubocop: disable CodeReuse/ActiveRecord
def extract_users(params)
return [] if params.nil?
@@ -680,7 +91,7 @@ module QuickActions
def group
strong_memoize(:group) do
- issuable.group if issuable.respond_to?(:group)
+ quick_action_target.group if quick_action_target.respond_to?(:group)
end
end
diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb
index dad6e85fb56..5f8b89f2a24 100644
--- a/app/uploaders/object_storage.rb
+++ b/app/uploaders/object_storage.rb
@@ -278,8 +278,12 @@ module ObjectStorage
self.class.object_store_credentials
end
+ # Set ACL of uploaded objects to not-public (fog-aws)[1] or no ACL at all
+ # (fog-google). Value is ignored by other supported backends (fog-aliyun,
+ # fog-openstack, fog-rackspace)
+ # [1]: https://github.com/fog/fog-aws/blob/daa50bb3717a462baf4d04d0e0cbfc18baacb541/lib/fog/aws/models/storage/file.rb#L152-L159
def fog_public
- false
+ nil
end
def delete_migrated_file(migrated_file)
diff --git a/app/validators/cluster_name_validator.rb b/app/validators/cluster_name_validator.rb
index 85fd63f08e5..79c9c67ae58 100644
--- a/app/validators/cluster_name_validator.rb
+++ b/app/validators/cluster_name_validator.rb
@@ -5,7 +5,9 @@
# Custom validator for ClusterName.
class ClusterNameValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
- if record.managed?
+ if record.provided_by_user?
+ record.errors.add(attribute, " has to be present") unless value.present?
+ else
if record.persisted? && record.name_changed?
record.errors.add(attribute, " can not be changed because it's synchronized with provider")
end
@@ -17,10 +19,6 @@ class ClusterNameValidator < ActiveModel::EachValidator
unless value =~ Gitlab::Regex.kubernetes_namespace_regex
record.errors.add(attribute, Gitlab::Regex.kubernetes_namespace_regex_message)
end
- else
- unless value.present?
- record.errors.add(attribute, " has to be present")
- end
end
end
end
diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml
index ecf2b1d60ba..423472324fe 100644
--- a/app/views/admin/runners/_runner.html.haml
+++ b/app/views/admin/runners/_runner.html.haml
@@ -50,7 +50,7 @@
.table-mobile-header{ role: 'rowheader' }= _('Tags')
.table-mobile-content
- runner.tags.map(&:name).sort.each do |tag|
- %span.badge.badge-primary
+ %span.badge.badge-primary.str-truncated.has-tooltip{ title: tag }
= tag
.table-section.section-10
diff --git a/app/views/clusters/clusters/_advanced_settings.html.haml b/app/views/clusters/clusters/_advanced_settings.html.haml
index 7037c80aa6b..8005dcbf65f 100644
--- a/app/views/clusters/clusters/_advanced_settings.html.haml
+++ b/app/views/clusters/clusters/_advanced_settings.html.haml
@@ -1,5 +1,5 @@
- if can?(current_user, :admin_cluster, @cluster)
- - if @cluster.managed?
+ - unless @cluster.provided_by_user?
.append-bottom-20
%label.append-bottom-10
= s_('ClusterIntegration|Google Kubernetes Engine')
diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml
index 61188c6fa0b..62b947ca40d 100644
--- a/app/views/clusters/clusters/show.html.haml
+++ b/app/views/clusters/clusters/show.html.haml
@@ -53,5 +53,5 @@
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p= s_("ClusterIntegration|Advanced options on this Kubernetes cluster's integration")
- .settings-content
+ .settings-content#advanced-settings-section
= render 'advanced_settings'
diff --git a/app/views/clusters/platforms/kubernetes/_form.html.haml b/app/views/clusters/platforms/kubernetes/_form.html.haml
index 4a452b83112..b5ddca7ccb9 100644
--- a/app/views/clusters/platforms/kubernetes/_form.html.haml
+++ b/app/views/clusters/platforms/kubernetes/_form.html.haml
@@ -2,7 +2,7 @@
= form_errors(cluster)
.form-group
- - if cluster.managed?
+ - if cluster.read_only_kubernetes_platform_fields?
%label.append-bottom-10{ for: 'cluster-name' }
= s_('ClusterIntegration|Kubernetes cluster name')
.input-group
@@ -18,27 +18,27 @@
.form-group
= platform_field.label :api_url, s_('ClusterIntegration|API URL')
.input-group
- = platform_field.text_field :api_url, class: 'form-control js-select-on-focus', placeholder: s_('ClusterIntegration|API URL'), readonly: cluster.managed?
- - if cluster.managed?
+ = platform_field.text_field :api_url, class: 'form-control js-select-on-focus', placeholder: s_('ClusterIntegration|API URL'), readonly: cluster.read_only_kubernetes_platform_fields?
+ - if cluster.read_only_kubernetes_platform_fields?
%span.input-group-append
= clipboard_button(text: platform.api_url, title: s_('ClusterIntegration|Copy API URL'), class: 'input-group-text btn-default')
.form-group
= platform_field.label :ca_cert, s_('ClusterIntegration|CA Certificate')
.input-group
- = platform_field.text_area :ca_cert, class: 'form-control js-select-on-focus', placeholder: s_('ClusterIntegration|Certificate Authority bundle (PEM format)'), readonly: cluster.managed?
- - if cluster.managed?
+ = platform_field.text_area :ca_cert, class: 'form-control js-select-on-focus', placeholder: s_('ClusterIntegration|Certificate Authority bundle (PEM format)'), readonly: cluster.read_only_kubernetes_platform_fields?
+ - if cluster.read_only_kubernetes_platform_fields?
%span.input-group-append.clipboard-addon
= clipboard_button(text: platform.ca_cert, title: s_('ClusterIntegration|Copy CA Certificate'), class: 'input-group-text btn-blank')
.form-group
= platform_field.label :token, s_('ClusterIntegration|Token')
.input-group
- = platform_field.text_field :token, class: 'form-control js-cluster-token js-select-on-focus', type: 'password', placeholder: s_('ClusterIntegration|Token'), readonly: cluster.managed?
+ = platform_field.text_field :token, class: 'form-control js-cluster-token js-select-on-focus', type: 'password', placeholder: s_('ClusterIntegration|Token'), readonly: cluster.read_only_kubernetes_platform_fields?
%span.input-group-append
%button.btn.btn-default.input-group-text.js-show-cluster-token{ type: 'button' }
= s_('ClusterIntegration|Show')
- - if cluster.managed?
+ - if cluster.read_only_kubernetes_platform_fields?
= clipboard_button(text: platform.token, title: s_('ClusterIntegration|Copy Token'), class: 'btn-default')
- if cluster.allow_user_defined_namespace?
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 6b33189d1cf..3a0c2b9c284 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -357,12 +357,12 @@
= link_to project_settings_repository_path(@project), title: _('Repository') do
%span
= _('Repository')
- - if @project.feature_available?(:builds, current_user)
+ - if !@project.archived? && @project.feature_available?(:builds, current_user)
= nav_link(controller: :ci_cd) do
= link_to project_settings_ci_cd_path(@project), title: _('CI / CD') do
%span
= _('CI / CD')
- - if settings_operations_available?
+ - if !@project.archived? && settings_operations_available?
= nav_link(controller: [:operations]) do
= link_to project_settings_operations_path(@project), title: _('Operations') do
= _('Operations')
diff --git a/app/views/notify/_note_email.text.erb b/app/views/notify/_note_email.text.erb
index 5a67214059c..fae8fa3ccf3 100644
--- a/app/views/notify/_note_email.text.erb
+++ b/app/views/notify/_note_email.text.erb
@@ -1,5 +1,6 @@
<% note = local_assigns.fetch(:note, @note) -%>
<% diff_limit = local_assigns.fetch(:diff_limit, nil) -%>
+<% target_url = local_assigns.fetch(:target_url, @target_url) -%>
<% discussion = note.discussion if note.part_of_discussion? -%>
<% if discussion && !discussion.individual_note? -%>
@@ -13,6 +14,9 @@
<%= " on #{discussion.file_path}" -%>
<% end -%>
<%= ":" -%>
+<% if discussion.diff_discussion? || !discussion.new_discussion? -%>
+<%= " #{target_url}" -%>
+<% end -%>
<% elsif Gitlab::CurrentSettings.email_author_in_body -%>
diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml
index e1a9ec0217e..10575aa68b1 100644
--- a/app/views/projects/_md_preview.html.haml
+++ b/app/views/projects/_md_preview.html.haml
@@ -7,7 +7,7 @@
= _('This merge request is locked.')
= _('Only project members can comment.')
-.md-area
+.md-area.position-relative
.md-header
%ul.nav.nav-tabs.nav-links.clearfix
%li.md-header-tab.active
diff --git a/changelogs/unreleased/10735-geo-gitlab-revision-can-return-not-consistent-results.yml b/changelogs/unreleased/10735-geo-gitlab-revision-can-return-not-consistent-results.yml
new file mode 100644
index 00000000000..2360295b022
--- /dev/null
+++ b/changelogs/unreleased/10735-geo-gitlab-revision-can-return-not-consistent-results.yml
@@ -0,0 +1,5 @@
+---
+title: Use a fixed git abbrev parameter when we fetch a git revision
+merge_request: 26707
+author:
+type: fixed
diff --git a/changelogs/unreleased/24936-remove-type-from-review-app-name.yml b/changelogs/unreleased/24936-remove-type-from-review-app-name.yml
new file mode 100644
index 00000000000..639333264f6
--- /dev/null
+++ b/changelogs/unreleased/24936-remove-type-from-review-app-name.yml
@@ -0,0 +1,5 @@
+---
+title: Remove unnecessary folder prefix from environment name
+merge_request: 25600
+author:
+type: changed
diff --git a/changelogs/unreleased/53210-add-uniq-constraints-on-issues-and-mrs-labels.yml b/changelogs/unreleased/53210-add-uniq-constraints-on-issues-and-mrs-labels.yml
new file mode 100644
index 00000000000..f9cd8716b92
--- /dev/null
+++ b/changelogs/unreleased/53210-add-uniq-constraints-on-issues-and-mrs-labels.yml
@@ -0,0 +1,5 @@
+---
+title: add a uniq constraints on issues and mrs labels
+merge_request: 25435
+author: Antoine Huret
+type: fixed
diff --git a/changelogs/unreleased/57669-fix-bug-clicking-file-header-refreshes-page.yml b/changelogs/unreleased/57669-fix-bug-clicking-file-header-refreshes-page.yml
new file mode 100644
index 00000000000..c6161870096
--- /dev/null
+++ b/changelogs/unreleased/57669-fix-bug-clicking-file-header-refreshes-page.yml
@@ -0,0 +1,6 @@
+---
+title: Scroll to diff file content when clicking on file header name and it is not
+ a link to other page
+merge_request: !26422
+author:
+type: fixed
diff --git a/changelogs/unreleased/58793-fix-nav-links-archived-project.yml b/changelogs/unreleased/58793-fix-nav-links-archived-project.yml
new file mode 100644
index 00000000000..a8250804c34
--- /dev/null
+++ b/changelogs/unreleased/58793-fix-nav-links-archived-project.yml
@@ -0,0 +1,5 @@
+---
+title: "Disable inaccessible navigation links upon archiving a project"
+merge_request: 26020
+author: Elias Werberich
+type: fixed
diff --git a/changelogs/unreleased/58971-sentry-api-keyerror.yml b/changelogs/unreleased/58971-sentry-api-keyerror.yml
new file mode 100644
index 00000000000..0f195c4b4f7
--- /dev/null
+++ b/changelogs/unreleased/58971-sentry-api-keyerror.yml
@@ -0,0 +1,5 @@
+---
+title: Handle missing keys in sentry api response
+merge_request: 26264
+author:
+type: fixed
diff --git a/changelogs/unreleased/59441-add-base-domain-to-cluster-api.yml b/changelogs/unreleased/59441-add-base-domain-to-cluster-api.yml
new file mode 100644
index 00000000000..cb5cbba4e92
--- /dev/null
+++ b/changelogs/unreleased/59441-add-base-domain-to-cluster-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add cluster domain to Project Cluster API
+merge_request: 26735
+author:
+type: other
diff --git a/changelogs/unreleased/check-mergeability-in-merge-to-ref-service.yml b/changelogs/unreleased/check-mergeability-in-merge-to-ref-service.yml
new file mode 100644
index 00000000000..9f615bbb54a
--- /dev/null
+++ b/changelogs/unreleased/check-mergeability-in-merge-to-ref-service.yml
@@ -0,0 +1,5 @@
+---
+title: Check mergeability in MergeToRefService
+merge_request: 26757
+author:
+type: changed
diff --git a/changelogs/unreleased/fix-container-scanning-on-k8s.yml b/changelogs/unreleased/fix-container-scanning-on-k8s.yml
new file mode 100644
index 00000000000..f4500370a0b
--- /dev/null
+++ b/changelogs/unreleased/fix-container-scanning-on-k8s.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Container Scanning in Kubernetes Runners
+merge_request: 26793
+author:
+type: changed
diff --git a/changelogs/unreleased/fix-transfer-group-possibilities.yml b/changelogs/unreleased/fix-transfer-group-possibilities.yml
new file mode 100644
index 00000000000..ebefb47b3da
--- /dev/null
+++ b/changelogs/unreleased/fix-transfer-group-possibilities.yml
@@ -0,0 +1,5 @@
+---
+title: Fix group transfer selection possibilities
+merge_request: 26123
+author: Peter Marko
+type: fixed
diff --git a/changelogs/unreleased/nfriend-css-updates-for-gitlab-design-system-compliance.yml b/changelogs/unreleased/nfriend-css-updates-for-gitlab-design-system-compliance.yml
new file mode 100644
index 00000000000..8cde0958f7a
--- /dev/null
+++ b/changelogs/unreleased/nfriend-css-updates-for-gitlab-design-system-compliance.yml
@@ -0,0 +1,5 @@
+---
+title: Update `border-radius` of form controls and remove extra space above page titles
+merge_request: 24497
+author:
+type: fixed
diff --git a/changelogs/unreleased/persist-fulll-ref-path-for-mr-pipelines.yml b/changelogs/unreleased/persist-fulll-ref-path-for-mr-pipelines.yml
new file mode 100644
index 00000000000..ca42a26e8ff
--- /dev/null
+++ b/changelogs/unreleased/persist-fulll-ref-path-for-mr-pipelines.yml
@@ -0,0 +1,5 @@
+---
+title: Create MR pipelines with `refs/merge-requests/:iid/head`
+merge_request: 25504
+author:
+type: changed
diff --git a/changelogs/unreleased/related-mr-link-cutoff.yml b/changelogs/unreleased/related-mr-link-cutoff.yml
new file mode 100644
index 00000000000..8cf77b6231a
--- /dev/null
+++ b/changelogs/unreleased/related-mr-link-cutoff.yml
@@ -0,0 +1,5 @@
+---
+title: Don't cutoff letters in MR and Issue links
+merge_request: 25910
+author: gfyoung
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-gitaly-find-commit-caching.yml b/changelogs/unreleased/sh-fix-gitaly-find-commit-caching.yml
new file mode 100644
index 00000000000..16d349c407c
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-gitaly-find-commit-caching.yml
@@ -0,0 +1,5 @@
+---
+title: Allow ref name caching CommitService#find_commit
+merge_request: 26248
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-fix-project-branches-merge-status.yml b/changelogs/unreleased/sh-fix-project-branches-merge-status.yml
new file mode 100644
index 00000000000..65f41b3faf9
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-project-branches-merge-status.yml
@@ -0,0 +1,5 @@
+---
+title: Fix API /project/:id/branches not returning correct merge status
+merge_request: 26785
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-force-gc-after-import.yml b/changelogs/unreleased/sh-force-gc-after-import.yml
new file mode 100644
index 00000000000..755d66c1607
--- /dev/null
+++ b/changelogs/unreleased/sh-force-gc-after-import.yml
@@ -0,0 +1,5 @@
+---
+title: Force a full GC after importing a project
+merge_request: 26803
+author:
+type: performance
diff --git a/config/helpers/is_ee_env.js b/config/helpers/is_ee_env.js
new file mode 100644
index 00000000000..1fdbca591c0
--- /dev/null
+++ b/config/helpers/is_ee_env.js
@@ -0,0 +1,9 @@
+const fs = require('fs');
+const path = require('path');
+
+const ROOT_PATH = path.resolve(__dirname, '../..');
+
+module.exports =
+ process.env.EE !== undefined
+ ? JSON.parse(process.env.EE)
+ : fs.existsSync(path.join(ROOT_PATH, 'ee'));
diff --git a/config/initializers/jira.rb b/config/initializers/jira.rb
new file mode 100644
index 00000000000..05f784a6a2a
--- /dev/null
+++ b/config/initializers/jira.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+# Changes JIRA DVCS user agent requests in order to be successfully handled
+# by our API.
+#
+# Gitlab::Jira::Middleware is only defined on EE
+#
+# Use safe_constantize because the class may exist but has not been loaded yet
+if "Gitlab::Jira::Middleware".safe_constantize
+ Rails.application.config.middleware.use(Gitlab::Jira::Middleware)
+end
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 20b3f4c0264..9a37856a99e 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -1,4 +1,3 @@
-const fs = require('fs');
const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
@@ -12,10 +11,7 @@ const ROOT_PATH = path.resolve(__dirname, '..');
const CACHE_PATH = process.env.WEBPACK_CACHE_PATH || path.join(ROOT_PATH, 'tmp/cache');
const IS_PRODUCTION = process.env.NODE_ENV === 'production';
const IS_DEV_SERVER = process.argv.join(' ').indexOf('webpack-dev-server') !== -1;
-const IS_EE =
- process.env.EE !== undefined
- ? JSON.parse(process.env.EE)
- : fs.existsSync(path.join(ROOT_PATH, 'ee'));
+const IS_EE = require('./helpers/is_ee_env');
const DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost';
const DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808;
const DEV_SERVER_LIVERELOAD = IS_DEV_SERVER && process.env.DEV_SERVER_LIVERELOAD !== 'false';
diff --git a/db/migrate/20190325165127_add_managed_to_cluster.rb b/db/migrate/20190325165127_add_managed_to_cluster.rb
new file mode 100644
index 00000000000..e960df9d502
--- /dev/null
+++ b/db/migrate/20190325165127_add_managed_to_cluster.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddManagedToCluster < ActiveRecord::Migration[5.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+
+ def up
+ add_column_with_default(:clusters, :managed, :boolean, default: true)
+ end
+
+ def down
+ remove_column(:clusters, :managed)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 7cc09e56285..8197e860996 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20190322132835) do
+ActiveRecord::Schema.define(version: 20190325165127) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -670,6 +670,7 @@ ActiveRecord::Schema.define(version: 20190322132835) do
t.string "environment_scope", default: "*", null: false
t.integer "cluster_type", limit: 2, default: 3, null: false
t.string "domain"
+ t.boolean "managed", default: true, null: false
t.index ["enabled"], name: "index_clusters_on_enabled", using: :btree
t.index ["user_id"], name: "index_clusters_on_user_id", using: :btree
end
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 288ce376687..17d72b96a51 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -125,7 +125,7 @@ The Pages daemon doesn't listen to the outside world.
pages_external_url 'http://example.io'
```
-1. [Reconfigure GitLab][reconfigure]
+1. [Reconfigure GitLab][reconfigure].
Watch the [video tutorial][video-admin] for this configuration.
@@ -157,7 +157,22 @@ outside world.
where `pages-nginx.crt` and `pages-nginx.key` are the SSL cert and key,
respectively.
-1. [Reconfigure GitLab][reconfigure]
+1. [Reconfigure GitLab][reconfigure].
+
+### Additional configuration for Docker container
+
+The GitLab Pages daemon will not have permissions to bind mounts when it runs
+in a Docker container. To overcome this issue you'll need to change the chroot
+behavior:
+
+1. Edit `/etc/gitlab/gitlab.rb`.
+1. Set the `inplace_chroot` to `true` for GitLab Pages:
+
+ ```shell
+ gitlab_pages['inplace_chroot'] = true
+ ```
+
+1. [Reconfigure GitLab][reconfigure].
## Advanced configuration
@@ -195,7 +210,7 @@ world. Custom domains are supported, but no TLS.
`192.0.2.2` and `2001::2` are the secondary IPs the GitLab Pages daemon
listens on. If you don't have IPv6, you can omit the IPv6 address.
-1. [Reconfigure GitLab][reconfigure]
+1. [Reconfigure GitLab][reconfigure].
### Custom domains with TLS support
@@ -229,7 +244,7 @@ world. Custom domains and TLS are supported.
`192.0.2.2` and `2001::2` are the secondary IPs where the GitLab Pages daemon
listens on. If you don't have IPv6, you can omit the IPv6 address.
-1. [Reconfigure GitLab][reconfigure]
+1. [Reconfigure GitLab][reconfigure].
### Custom domain verification
@@ -287,7 +302,7 @@ Follow the steps below to configure verbose logging of GitLab Pages daemon.
gitlab_pages['log_verbose'] = true
```
-1. [Reconfigure GitLab][reconfigure]
+1. [Reconfigure GitLab][reconfigure].
## Change storage path
@@ -302,7 +317,7 @@ are stored.
gitlab_rails['pages_path'] = "/mnt/storage/pages"
```
-1. [Reconfigure GitLab][reconfigure]
+1. [Reconfigure GitLab][reconfigure].
## Configure listener for reverse proxy requests
@@ -325,7 +340,7 @@ Omnibus GitLab 11.1.
gitlab_pages['listen_proxy'] = "localhost:10080"
```
-1. [Reconfigure GitLab][reconfigure]
+1. [Reconfigure GitLab][reconfigure].
## Set maximum pages size
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 09546fcac3f..c8c282a71d9 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -155,6 +155,32 @@ Example response:
}
```
+GitLab supports [form encoding](../README.md#encoding-api-parameters-of-array-and-hash-types). The following is an example using Commit API with form encoding:
+
+```bash
+curl --request POST \
+ --form "branch=master" \
+ --form "commit_message=some commit message" \
+ --form "start_branch=master" \
+ --form "actions[][action]=create" \
+ --form "actions[][file_path]=foo/bar" \
+ --form "actions[][content]=</path/to/local.file" \
+ --form "actions[][action]=delete" \
+ --form "actions[][file_path]=foo/bar2" \
+ --form "actions[][action]=move" \
+ --form "actions[][file_path]=foo/bar3" \
+ --form "actions[][previous_path]=foo/bar4" \
+ --form "actions[][content]=</path/to/local1.file" \
+ --form "actions[][action]=update" \
+ --form "actions[][file_path]=foo/bar5" \
+ --form "actions[][content]=</path/to/local2.file" \
+ --form "actions[][action]=chmod" \
+ --form "actions[][file_path]=foo/bar5" \
+ --form "actions[][execute_filemode]=true" \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/1/repository/commits"
+```
+
## Get a single commit
Get a specific commit identified by the commit hash or name of a branch or tag.
@@ -196,9 +222,9 @@ Example response:
"last_pipeline" : {
"id": 8,
"ref": "master",
- "sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0"
+ "sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0",
"status": "created"
- }
+ },
"stats": {
"additions": 15,
"deletions": 10,
diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md
index 8efb98fe1fc..02334f0298e 100644
--- a/doc/api/project_clusters.md
+++ b/doc/api/project_clusters.md
@@ -33,6 +33,7 @@ Example response:
{
"id":18,
"name":"cluster-1",
+ "domain":"example.com",
"created_at":"2019-01-02T20:18:12.563Z",
"provider_type":"user",
"platform_type":"kubernetes",
@@ -90,6 +91,7 @@ Example response:
{
"id":18,
"name":"cluster-1",
+ "domain":"example.com",
"created_at":"2019-01-02T20:18:12.563Z",
"provider_type":"user",
"platform_type":"kubernetes",
@@ -157,6 +159,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of the project owned by the authenticated user |
| `name` | String | yes | The name of the cluster |
+| `domain` | String | no | The [base domain](../user/project/clusters/index.md#base_domain) of the cluster |
| `enabled` | Boolean | no | Determines if cluster is active or not, defaults to true |
| `platform_kubernetes_attributes[api_url]` | String | yes | The URL to access the Kubernetes API |
| `platform_kubernetes_attributes[token]` | String | yes | The token to authenticate against Kubernetes |
@@ -247,6 +250,7 @@ Parameters:
| `id` | integer | yes | The ID of the project owned by the authenticated user |
| `cluster_id` | integer | yes | The ID of the cluster |
| `name` | String | no | The name of the cluster |
+| `domain` | String | no | The [base domain](../user/project/clusters/index.md#base_domain) of the cluster |
| `platform_kubernetes_attributes[api_url]` | String | no | The URL to access the Kubernetes API |
| `platform_kubernetes_attributes[token]` | String | no | The token to authenticate against Kubernetes |
| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate |
@@ -262,7 +266,7 @@ Example request:
```bash
curl --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/projects/26/clusters/24 \
-H "Content-Type:application/json" \
--X PUT --data '{"name":"new-cluster-name","api_url":"https://new-api-url.com"}'
+-X PUT --data '{"name":"new-cluster-name","domain":"new-domain.com","api_url":"https://new-api-url.com"}'
```
Example response:
@@ -271,6 +275,7 @@ Example response:
{
"id":24,
"name":"new-cluster-name",
+ "domain":"new-domain.com",
"created_at":"2019-01-03T21:53:40.610Z",
"provider_type":"user",
"platform_type":"kubernetes",
diff --git a/doc/api/services.md b/doc/api/services.md
index 03d0a80aa64..1f84e2de7de 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -522,7 +522,7 @@ Parameters:
| `username` | string | yes | The username of the user created to be used with GitLab/JIRA. |
| `password` | string | yes | The password of the user created to be used with GitLab/JIRA. |
| `active` | boolean | no | Activates or deactivates the service. Defaults to false (deactivated). |
-| `jira_issue_transition_id` | integer | no | The ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`. |
+| `jira_issue_transition_id` | string | no | The ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`. |
### Delete JIRA service
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 47810a8b7b6..913e9d4d789 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -43,28 +43,27 @@ For complete control, you can manually configure GitLab CI/CD.
With basic knowledge of how GitLab CI/CD works, the following documentation extends your knowledge
into more features:
-| Topic | Description |
-|:--------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------|
-| [Creating and using CI/CD pipelines](pipelines.md) | Understand, visualize, create, and use CI/CD pipelines. |
-| [CI/CD Variables](variables/README.md) | How environment variables can be configured and made available in pipelines. |
-| [Where variables can be used](variables/where_variables_can_be_used.md) | A deeper look into where and how CI/CD variables can be used. |
-| [User](../user/permissions.md#gitlab-cicd-permissions) and [job](../user/permissions.md#job-permissions) permissions | Learn about the access levels a user can have for performing certain CI actions. |
-| [Configuring GitLab Runners](runners/README.md) | Documentation for configuring [GitLab Runner](https://docs.gitlab.com/runner/). |
-| [Introduction to environments and deployments](environments.md) | Learn how to separate your jobs into environments and use them for different purposes like testing, building and, deploying. |
-| [Job artifacts](../user/project/pipelines/job_artifacts.md) | Learn about the output of jobs. |
-| [Cache dependencies in GitLab CI/CD](caching/index.md) | Discover how to speed up pipelines using caching. |
-| [Using Git submodules with GitLab CI](git_submodules.md) | How to run your CI jobs when using Git submodules. |
-| [Pipelines for merge requests](merge_request_pipelines/index.md) | Create pipelines specifically for merge requests. |
-| [Using SSH keys with GitLab CI/CD](ssh_keys/README.md) | Use SSH keys in your build environment. |
-| [Triggering pipelines through the API](triggers/README.md) | Use the GitLab API to trigger a pipeline. |
-| [Pipeline schedules](../user/project/pipelines/schedules.md) | Trigger pipelines on a schedule. |
-| [Connecting GitLab with a Kubernetes cluster](../user/project/clusters/index.md) | Integrate one or more Kubernetes clusters to your project. |
-| [ChatOps](chatops/README.md) | Trigger CI jobs from chat, with results sent back to the channel. |
-| [Interactive web terminals](interactive_web_terminal/index.md) | Open an interactive web terminal to debug the running jobs. |
-| [Review Apps](review_apps/index.md) | Configure GitLab CI/CD to preview code changes in a per-branch basis. |
-| [Deploy Boards](https://docs.gitlab.com/ee/user/project/deploy_boards.html) **[PREMIUM]** | Check the current health and status of each CI/CD environment running on Kubernetes. |
-| [GitLab CI/CD for external repositories](https://docs.gitlab.com/ee/ci/ci_cd_for_external_repos/index.html) **[PREMIUM]** | Get the benefits of GitLab CI/CD combined with repositories in GitHub and BitBucket Cloud. |
-| [Protected environments](https://docs.gitlab.com/ce/ci/environments/protected_environments.html) **[PREMIUM]** | Ensure that only people with the right privileges can deploy to an environment. |
+| Topic | Description |
+|:--------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------|
+| [Creating and using CI/CD pipelines](pipelines.md) | Understand, visualize, create, and use CI/CD pipelines. |
+| [CI/CD Variables](variables/README.md) | How environment variables can be configured and made available in pipelines. |
+| [Where variables can be used](variables/where_variables_can_be_used.md) | A deeper look into where and how CI/CD variables can be used. |
+| [User](../user/permissions.md#gitlab-cicd-permissions) and [job](../user/permissions.md#job-permissions) permissions | Learn about the access levels a user can have for performing certain CI actions. |
+| [Configuring GitLab Runners](runners/README.md) | Documentation for configuring [GitLab Runner](https://docs.gitlab.com/runner/). |
+| [Environments and deployments](environments.md) | Deploy the output of jobs into environments for reviewing, staging, and production. |
+| [Job artifacts](../user/project/pipelines/job_artifacts.md) | Learn about the output of jobs. |
+| [Cache dependencies in GitLab CI/CD](caching/index.md) | Discover how to speed up pipelines using caching. |
+| [Using Git submodules with GitLab CI](git_submodules.md) | How to run your CI jobs when using Git submodules. |
+| [Pipelines for merge requests](merge_request_pipelines/index.md) | Create pipelines specifically for merge requests. |
+| [Using SSH keys with GitLab CI/CD](ssh_keys/README.md) | Use SSH keys in your build environment. |
+| [Triggering pipelines through the API](triggers/README.md) | Use the GitLab API to trigger a pipeline. |
+| [Pipeline schedules](../user/project/pipelines/schedules.md) | Trigger pipelines on a schedule. |
+| [Connecting GitLab with a Kubernetes cluster](../user/project/clusters/index.md) | Integrate one or more Kubernetes clusters to your project. |
+| [ChatOps](chatops/README.md) | Trigger CI jobs from chat, with results sent back to the channel. |
+| [Interactive web terminals](interactive_web_terminal/index.md) | Open an interactive web terminal to debug the running jobs. |
+| [Review Apps](review_apps/index.md) | Configure GitLab CI/CD to preview code changes in a per-branch basis. |
+| [Deploy Boards](https://docs.gitlab.com/ee/user/project/deploy_boards.html) **[PREMIUM]** | Check the current health and status of each CI/CD environment running on Kubernetes. |
+| [GitLab CI/CD for external repositories](https://docs.gitlab.com/ee/ci/ci_cd_for_external_repos/index.html) **[PREMIUM]** | Get the benefits of GitLab CI/CD combined with repositories in GitHub and BitBucket Cloud. |
### GitLab Pages
@@ -121,7 +120,7 @@ See also the [Why CI/CD?](https://docs.google.com/presentation/d/1OGgk2Tcxbpl7DJ
As GitLab CI/CD has evolved, certain breaking changes have been necessary. These are:
-- [CI variables renaming for GitLab 9.0](variables/README.md#gitlab-90-renaming). Read about the
+- [CI variables renaming for GitLab 9.0](variables/deprecated_variables.md#gitlab-90-renamed-variables). Read about the
deprecated CI variables and what you should use for GitLab 9.0+.
- [New CI job permissions model](../user/project/new_ci_build_permissions_model.md).
See what changed in GitLab 8.12 and how that affects your jobs.
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index 05d392d54cb..54493bc2922 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -1,45 +1,65 @@
-# Introduction to environments and deployments
+# Environments and deployments
> Introduced in GitLab 8.9.
-During the development of software, there can be many stages until it's ready
-for public consumption. You sure want to first test your code and then deploy it
-in a testing or staging environment before you release it to the public. That
-way you can prevent bugs not only in your software, but in the deployment
-process as well.
+Environments allow control of the continuous deployment of your software,
+all within GitLab.
-GitLab CI is capable of not only testing or building your projects, but also
+## Introduction
+
+There are many stages required in the software development process before the software is ready
+for public consumption.
+
+For example:
+
+1. Develop your code.
+1. Test your code.
+1. Deploy your code into a testing or staging environment before you release it to the public.
+
+This helps prevent bugs not only in your software, but in the deployment process as well.
+
+GitLab CI/CD is capable of not only testing or building your projects, but also
deploying them in your infrastructure, with the added benefit of giving you a
way to track your deployments. In other words, you can always know what is
currently being deployed or has been deployed on your servers.
-## Overview
+It's important to know that:
-With environments, you can control the Continuous Deployment of your software
-all within GitLab. All you need to do is define them in your project's
-[`.gitlab-ci.yml`][yaml] as we will explore below. GitLab provides a full
-history of your deployments per every environment.
+- Environments are like tags for your CI jobs, describing where code gets deployed.
+- Deployments are created when [jobs](yaml/README.md#introduction) deploy versions of code to environments,
+ so every environment can have one or more deployments.
-Environments are like tags for your CI jobs, describing where code gets deployed.
-Deployments are created when [jobs](yaml/README.md#introduction) deploy versions of code to environments,
-so every environment can have one or more deployments. GitLab keeps track of
-your deployments, so you always know what is currently being deployed on your
-servers. If you have a deployment service such as [Kubernetes][kube]
+GitLab:
+
+- Provides a full history of your deployments per every environment.
+- Keeps track of your deployments, so you always know what is currently being deployed on your
+ servers.
+
+If you have a deployment service such as [Kubernetes](../user/project/clusters/index.md)
enabled for your project, you can use it to assist with your deployments, and
can even access a [web terminal](#web-terminals) for your environment from within GitLab!
-To better understand how environments and deployments work, let's consider an
-example. We assume that you have already created a project in GitLab and set up
-a Runner. The example will cover the following:
+## Configuring environments
+
+Configuring environments involves:
+
+1. Understanding how [pipelines](pipelines.md) work.
+1. Defining environments in your project's [`.gitlab-ci.yml`](yaml/README.md) file.
+
+The rest of this section illustrates how to configure environments and deployments using an example.
+It assumes you have already:
-- We are developing an application
-- We want to run tests and build our app on all branches
-- Our default branch is `master`
-- We deploy the app only when a pipeline on `master` branch is run
+- Created a [project](../gitlab-basics/create-project.md) in GitLab.
+- Set up [a Runner](runners/README.md).
-Let's see how it all ties together.
+In the scenario:
-## Defining environments
+- We are developing an application.
+- We want to run tests and build our app on all branches.
+- Our default branch is `master`.
+- We deploy the app only when a pipeline on `master` branch is run.
+
+### Defining environments
Let's consider the following `.gitlab-ci.yml` example:
@@ -70,123 +90,64 @@ deploy_staging:
We have defined 3 [stages](yaml/README.md#stages):
-- test
-- build
-- deploy
+- `test`
+- `build`
+- `deploy`
The jobs assigned to these stages will run in this order. If a job fails, then
the jobs that are assigned to the next stage won't run, rendering the pipeline
-as failed. In our case, the `test` job will run first, then the `build` and
-lastly the `deploy_staging`. With this, we ensure that first the tests pass,
-then our app is able to be built successfully, and lastly we deploy to the
-staging server.
+as failed.
+
+In our case:
+
+- The `test` job will run first.
+- Then the `build` job.
+- Lastly the `deploy_staging` job.
+
+With this configuration, we ensure that:
+
+- The tests pass.
+- Our app is able to be built successfully.
+- Lastly we deploy to the staging server.
+NOTE: **Note:**
The `environment` keyword is just a hint for GitLab that this job actually
-deploys to this environment's `name`. It can also have a `url` which, as we
-will later see, is exposed in various places within GitLab. Each time a job that
-has an environment specified and succeeds, a deployment is recorded, remembering
+deploys to this environment's `name`. It can also have a `url` that is
+exposed in various places within GitLab. Each time a job that
+has an environment specified succeeds, a deployment is recorded, storing
the Git SHA and environment name.
-> **Note:**
+In summary, with the above `.gitlab-ci.yml` we have achieved the following:
+
+- All branches will run the `test` and `build` jobs.
+- The `deploy_staging` job will run [only](yaml/README.md#onlyexcept-basic) on the `master`
+ branch, which means all merge requests that are created from branches don't
+ get deployed to the staging server.
+- When a merge request is merged, all jobs will run and the `deploy_staging`
+ job will deploy our code to a staging server while the deployment
+ will be recorded in an environment named `staging`.
+
> Starting with GitLab 8.15, the environment name is exposed to the Runner in
> two forms: `$CI_ENVIRONMENT_NAME`, and `$CI_ENVIRONMENT_SLUG`. The first is
> the name given in `.gitlab-ci.yml` (with any variables expanded), while the
> second is a "cleaned-up" version of the name, suitable for use in URLs, DNS,
> etc.
->
-> **Note:**
+
> Starting with GitLab 9.3, the environment URL is exposed to the Runner via
> `$CI_ENVIRONMENT_URL`. The URL would be expanded from `.gitlab-ci.yml`, or if
> the URL was not defined there, the external URL from the environment would be
> used.
-To sum up, with the above `.gitlab-ci.yml` we have achieved that:
-
-- All branches will run the `test` and `build` jobs.
-- The `deploy_staging` job will run [only](yaml/README.md#onlyexcept-basic) on the `master`
- branch which means all merge requests that are created from branches don't
- get to deploy to the staging server
-- When a merge request is merged, all jobs will run and the `deploy_staging`
- in particular will deploy our code to a staging server while the deployment
- will be recorded in an environment named `staging`.
-
-Let's now see how that information is exposed within GitLab.
-
-## Viewing the current status of an environment
-
-The environment list under your project's **Operations > Environments**, is
-where you can find information of the last deployment status of an environment.
-
-Here's how the Environments page looks so far.
-
-![Environment view](img/environments_available.png)
-
-There's a bunch of information there, specifically you can see:
-
-- The environment's name with a link to its deployments
-- The last deployment ID number and who performed it
-- The job ID of the last deployment with its respective job name
-- The commit information of the last deployment such as who committed, to what
- branch and the Git SHA of the commit
-- The exact time the last deployment was performed
-- A button that takes you to the URL that you have defined under the
- `environment` keyword in `.gitlab-ci.yml`
-- A button that re-deploys the latest deployment, meaning it runs the job
- defined by the environment name for that specific commit
-
-> **Notes:**
->
-> - While you can create environments manually in the web interface, we recommend
-> that you define your environments in `.gitlab-ci.yml` first. They will
-> be automatically created for you after the first deploy.
-> - The environments page can only be viewed by Reporters and above. For more
-> information on the permissions, see the [permissions documentation][permissions].
-> - Only deploys that happen after your `.gitlab-ci.yml` is properly configured
-> will show up in the "Environment" and "Last deployment" lists.
-
-The information shown in the Environments page is limited to the latest
-deployments, but as you may have guessed an environment can have multiple
-deployments.
-
-## Viewing the deployment history of an environment
-
-GitLab keeps track of your deployments, so you always know what is currently
-being deployed on your servers. That way you can have the full history of your
-deployments per every environment right in your browser. Clicking on an
-environment will show the history of its deployments. Assuming you have deployed
-multiple times already, here's how a specific environment's page looks like.
-
-![Deployments](img/deployments_view.png)
-
-We can see the same information as when in the Environments page, but this time
-all deployments are shown. As you may have noticed, apart from the **Re-deploy**
-button there are now **Rollback** buttons for each deployment. Let's see how
-that works.
-
-## Rolling back changes
-
-You can't control everything, so sometimes things go wrong. When that unfortunate
-time comes GitLab has you covered. Simply by clicking the **Rollback** button
-that can be found in the deployments page
-(**Operations > Environments > `environment name`**) you can relaunch the
-job with the commit associated with it.
-
->**Note:**
-Bear in mind that your mileage will vary and it's entirely up to how you define
-the deployment process in the job's `script` whether the rollback succeeds or not.
-GitLab CI is just following orders.
+### Configuring manual deployments
-Thankfully that was the staging server that we had to rollback, and since we
-learn from our mistakes, we decided to not make the same again when we deploy
-to the production server. Enter manual actions for deployments.
+Converting automatically executed job into jobs requiring to a manual action involves
+adding `when: manual` to the job's configuration.
-## Manually deploying to environments
+To expand on the [previous example](#defining-environments), the following includes
+another job that deploys our app to a production server and is
+tracked by a `production` environment.
-Turning a job from running automatically to a manual action is as simple as
-adding `when: manual` to it. To expand on our previous example, let's add
-another job that this time deploys our app to a production server and is
-tracked by a `production` environment. The `.gitlab-ci.yml` looks like this
-so far:
+The `.gitlab-ci.yml` file for this is as follows:
```yaml
stages:
@@ -224,41 +185,62 @@ deploy_prod:
- master
```
-The `when: manual` action exposes a play button in GitLab's UI and the
-`deploy_prod` job will only be triggered if and when we click that play button.
-You can find it in the pipeline, job, environment, and deployment views.
+The `when: manual` action:
-| Pipelines | Single pipeline | Environments | Deployments | jobs |
-| --------- | ----------------| ------------ | ----------- | -------|
-| ![Pipelines manual action](img/environments_manual_action_pipelines.png) | ![Pipelines manual action](img/environments_manual_action_single_pipeline.png) | ![Environments manual action](img/environments_manual_action_environments.png) | ![Deployments manual action](img/environments_manual_action_deployments.png) | ![Builds manual action](img/environments_manual_action_jobs.png) |
+- Exposes a "play" button in GitLab's UI.
+- Means the `deploy_prod` job will only be triggered when the "play" button is clicked.
-Clicking on the play button in either of these places will trigger the
-`deploy_prod` job, and the deployment will be recorded under a new
+You can find the "play" button in the pipelines, environments, deployments, and jobs views.
+
+| View | Screenshot |
+|:----------------|:-------------------------------------------------------------------------------|
+| Pipelines | ![Pipelines manual action](img/environments_manual_action_pipelines.png) |
+| Single pipeline | ![Pipelines manual action](img/environments_manual_action_single_pipeline.png) |
+| Environments | ![Environments manual action](img/environments_manual_action_environments.png) |
+| Deployments | ![Deployments manual action](img/environments_manual_action_deployments.png) |
+| Jobs | ![Builds manual action](img/environments_manual_action_jobs.png) |
+
+Clicking on the play button in any view will trigger the `deploy_prod` job, and the deployment will be recorded under a new
environment named `production`.
->**Note:**
-Remember that if your environment's name is `production` (all lowercase), then
+NOTE: **Note:**
+If your environment's name is `production` (all lowercase),
it will get recorded in [Cycle Analytics](../user/project/cycle_analytics.md).
-Double the benefit!
-## Dynamic environments
+### Configuring dynamic environments
-As the name suggests, it is possible to create environments on the fly by just
-declaring their names dynamically in `.gitlab-ci.yml`. Dynamic environments is
-the basis of [Review apps](review_apps/index.md).
+Other environments are good for deploying to stable environments like staging or production.
-NOTE: **Note:**
-The `name` and `url` parameters can use most of the CI/CD variables,
-including [predefined](variables/README.md#predefined-environment-variables),
-[project/group ones](variables/README.md#variables) and
-[`.gitlab-ci.yml` variables](yaml/README.md#variables). You however cannot use variables
-defined under `script` or on the Runner's side. There are also other variables that
-are unsupported in the context of `environment:name`. You can read more about
-[where variables can be used](variables/where_variables_can_be_used.md).
-
-GitLab Runner exposes various [environment variables][variables] when a job runs,
-and as such, you can use them as environment names. Let's add another job in
-our example which will deploy to all branches except `master`:
+However, what about environments for branches other than `master`? Dynamic environments can be used to achieve these.
+
+Dynamic environments make it possible to create environments on the fly by
+declaring their names dynamically in `.gitlab-ci.yml`.
+
+Dynamic environments form the basis of [Review apps](review_apps/index.md).
+
+#### Allowed variables
+
+The `name` and `url` parameters for dynamic environments can use most available CI/CD variables,
+including:
+
+- [Predefined environment variables](variables/README.md#predefined-environment-variables)
+- [Project and group variables](variables/README.md#variables)
+- [`.gitlab-ci.yml` variables](yaml/README.md#variables)
+
+However, you cannot use variables defined:
+
+- Under `script`.
+- On the Runner's side.
+
+There are also other variables that are unsupported in the context of `environment:name`.
+For more information, see [Where variables can be used](variables/where_variables_can_be_used.md).
+
+#### Example configuration
+
+GitLab Runner exposes various [environment variables](variables/README.md) when a job runs and so
+you can use them as environment names.
+
+In the following example, a job will deploy to all branches except `master`:
```yaml
deploy_review:
@@ -274,39 +256,49 @@ deploy_review:
- master
```
-Let's break it down in pieces. The job's name is `deploy_review` and it runs
-on the `deploy` stage. The `script` at this point is fictional, you'd have to
-use your own based on your deployment. Then, we set the `environment` with the
-`environment:name` being `review/$CI_COMMIT_REF_NAME`. Now that's an interesting
-one. Since the [environment name][env-name] can contain slashes (`/`), we can
-use this pattern to distinguish between dynamic environments and the regular
-ones.
-
-So, the first part is `review`, followed by a `/` and then `$CI_COMMIT_REF_NAME`
-which takes the value of the branch name. Since `$CI_COMMIT_REF_NAME` itself may
-also contain `/`, or other characters that would be invalid in a domain name or
-URL, we use `$CI_ENVIRONMENT_SLUG` in the `environment:url` so that the
-environment can get a specific and distinct URL for each branch. In this case,
-given a `$CI_COMMIT_REF_NAME` of `100-Do-The-Thing`, the URL will be something
-like `https://100-do-the-4f99a2.example.com`. Again, the way you set up
-the web server to serve these requests is based on your setup.
-
-You could also use `$CI_COMMIT_REF_SLUG` in `environment:url`, e.g.:
-`https://$CI_COMMIT_REF_SLUG.example.com`. We use `$CI_ENVIRONMENT_SLUG`
-here because it is guaranteed to be unique, but if you're using a workflow like
-[GitLab Flow][gitlab-flow], collisions are very unlikely, and you may prefer
-environment names to be more closely based on the branch name - the example
-above would give you an URL like `https://100-do-the-thing.example.com`
-
-Last but not least, we tell the job to run [`only`](yaml/README.md#onlyexcept-basic) on branches
-[`except`](yaml/README.md#onlyexcept-basic) master.
-
->**Note:**
+In this example:
+
+- The job's name is `deploy_review` and it runs on the `deploy` stage.
+- We set the `environment` with the `environment:name` as `review/$CI_COMMIT_REF_NAME`.
+ Since the [environment name](yaml/README.md#environmentname) can contain slashes (`/`), we can
+ use this pattern to distinguish between dynamic environments and the regular ones.
+- We tell the job to run [`only`](yaml/README.md#onlyexcept-basic) on branches [`except`](yaml/README.md#onlyexcept-basic) `master`.
+
+For the value of:
+
+- `environment:name`, the first part is `review`, followed by a `/` and then `$CI_COMMIT_REF_NAME`,
+ which takes the value of the branch name.
+- `environment:url`, since `$CI_COMMIT_REF_NAME` itself may also contain `/`, or other characters that
+ would be invalid in a domain name or URL, we use `$CI_ENVIRONMENT_SLUG` so that the environment can get a specific and distinct URL for each branch.
+
+ For example, given a `$CI_COMMIT_REF_NAME` of `100-Do-The-Thing`, the URL will be something
+ like `https://100-do-the-4f99a2.example.com`. Again, the way you set up
+ the web server to serve these requests is based on your setup.
+
+ You could also use `$CI_COMMIT_REF_SLUG` in `environment:url`. For example, `https://$CI_COMMIT_REF_SLUG.example.com`.
+ We have used `$CI_ENVIRONMENT_SLUG` here because it is guaranteed to be unique. If you're using a workflow like
+ [GitLab Flow](../workflow/gitlab_flow.md), collisions are unlikely and you may prefer environment names to be more closely based on the branch name. The example
+ above would give you an URL like `https://100-do-the-thing.example.com`.
+
+NOTE: **Note:**
You are not bound to use the same prefix or only slashes in the dynamic
-environments' names (`/`), but as we will see later, this will enable the
-[grouping similar environments](#grouping-similar-environments) feature.
+environments' names (`/`). However, this will enable the [grouping similar environments](#grouping-similar-environments) feature.
+
+### Complete example
+
+The configuration in this section provides a full development workflow where your app is:
-The whole `.gitlab-ci.yml` looks like this so far:
+- Tested.
+- Built.
+- Deployed as a Review App.
+- Deployed to a staging server once the merge request is merged.
+- Finally, manually deployed to the production server.
+
+The following combines the previous configuration examples, including:
+
+- Defining [simple environments](#defining-environments) for testing, building, and deployment to staging.
+- Adding [manual actions](#configuring-manual-deployments) for deployment to production.
+- Creating [dynamic environments](#configuring-dynamic-environments) for deployments for reviewing.
```yaml
stages:
@@ -357,8 +349,9 @@ deploy_prod:
```
A more realistic example would include copying files to a location where a
-webserver (NGINX) could then read and serve. The example below will copy the
-`public` directory to `/srv/nginx/$CI_COMMIT_REF_SLUG/public`:
+webserver (for example, NGINX) could then read and serve.
+
+The example below will copy the `public` directory to `/srv/nginx/$CI_COMMIT_REF_SLUG/public`:
```yaml
review_app:
@@ -370,76 +363,155 @@ review_app:
url: https://$CI_COMMIT_REF_SLUG.example.com
```
-It is assumed that the user has already set up NGINX and GitLab Runner in the
-server this job will run on.
+This example requires that NGINX and GitLab Runner are set up on the server this job will run on.
+
+NOTE: **Note:**
+See the [limitations](#limitations) section for some edge cases regarding naming of your branches and Review Apps.
+
+The complete example provides the following workflow for developers:
+
+- Create a branch locally.
+- Make changes and commit them
+- Push the branch to GitLab.
+- Create a merge request.
+
+Behind the scenes, GitLab runner will:
+
+- Pick up the changes and start running the jobs.
+- Run the jobs sequentially as defined in `stages`:
+ - First, run the tests.
+ - If the tests succeed, build the app.
+ - If the build succeeds, the app will be is deployed to an environment with a name specific to the
+ branch.
+
+So now, every branch:
+
+- Gets its own environment.
+- Is deployed to its own location, with the added benefit of:
+ - Having a [history of deployments](#viewing-deployment-history).
+ - Being able to [rollback changes](#retrying-and-rolling-back) if needed.
+
+For more information on using the URL, see [Using the environment URL](#using-the-environment-url).
+
+### Protected environments
+
+Environments can be "protected", restricting access to them.
+
+For more information, see [Protected environments](environments/protected_environments.md).
+
+## Working with environments
+
+Having configured environments, GitLab provides many features to work with them. These are documented below.
+
+### Viewing environments and deployments
+
+A list of environments and deployment statuses is available on project's **Operations > Environments** page.
+
+For example:
+
+![Environment view](img/environments_available.png)
+
+This example shows:
+
+- The environment's name with a link to its deployments.
+- The last deployment ID number and who performed it.
+- The job ID of the last deployment with its respective job name.
+- The commit information of the last deployment such as who committed, to what
+ branch, and the Git SHA of the commit.
+- The exact time the last deployment was performed.
+- A button that takes you to the URL that you have defined under the
+ `environment` keyword in `.gitlab-ci.yml`.
+- A button that re-deploys the latest deployment, meaning it runs the job
+ defined by the environment name for that specific commit.
+
+The information shown in the **Environments** page is limited to the latest
+deployments, but an environment can have multiple deployments.
+
+> **Notes:**
+>
+> - While you can create environments manually in the web interface, we recommend
+> that you define your environments in `.gitlab-ci.yml` first. They will
+> be automatically created for you after the first deploy.
+> - The environments page can only be viewed by Reporters and above. For more
+> information on the permissions, see the [permissions documentation](../user/permissions.md).
+> - Only deploys that happen after your `.gitlab-ci.yml` is properly configured
+> will show up in the **Environment** and **Last deployment** lists.
+
+### Viewing deployment history
+
+GitLab keeps track of your deployments, so you:
->**Note:**
-Be sure to check out the [limitations](#limitations) section for some edge
-cases regarding naming of your branches and Review Apps.
+- Always know what is currently being deployed on your servers.
+- Can have the full history of your deployments per every environment.
----
+Clicking on an environment shows the history of its deployments. Here's an example **Environments** page
+with multiple deployments:
-The development workflow would now be:
+![Deployments](img/deployments_view.png)
+
+This view is similar to the **Environments** page, but all deployments are shown. Also in this view
+is a **Rollback** button. For more information, see [Retrying and rolling back](#retrying-and-rolling-back).
-- Developer creates a branch locally
-- Developer makes changes, commits and pushes the branch to GitLab
-- Developer creates a merge request
+### Retrying and rolling back
-Behind the scenes:
+If there is a problem with a deployment, you can retry it or roll it back.
-- GitLab Runner picks up the changes and starts running the jobs
-- The jobs run sequentially as defined in `stages`
- - First, the tests pass
- - Then, the job begins and successfully also passes
- - Lastly, the app is deployed to an environment with a name specific to the
- branch
+To retry or rollback a deployment:
-So now, every branch gets its own environment and is deployed to its own place
-with the added benefit of having a [history of deployments](#viewing-the-deployment-history-of-an-environment)
-and also being able to [rollback changes](#rolling-back-changes) if needed.
-Let's briefly see where URL that's defined in the environments is exposed.
+1. Navigate to **Operations > Environments**.
+1. Click on the environment.
+1. On the page that lists the deployment history for the environment, click the:
+ - **Rollback** button against a previously successful deployment, to roll back to that deployment.
+ - **Retry** button against the last deployment, to retry that deployment.
-## Making use of the environment URL
+NOTE: **Note:**
+The defined deployment process in the job's `script` determines whether the rollback succeeds or not.
+
+### Using the environment URL
The [environment URL](yaml/README.md#environmenturl) is exposed in a few
places within GitLab.
-| In a merge request widget as a link | In the Environments view as a button | In the Deployments view as a button |
-| -------------------- | ------------ | ----------- |
-| ![Environment URL in merge request](img/environments_mr_review_app.png) | ![Environment URL in environments](img/environments_available.png) | ![Environment URL in deployments](img/deployments_view.png) |
+These are:
+
+- In a merge request widget as a link:
+ ![Environment URL in merge request](img/environments_mr_review_app.png)
+- In the Environments view as a button:
+ ![Environment URL in environments](img/environments_available.png)
+- In the Deployments view as a button:
+ ![Environment URL in deployments](img/deployments_view.png)
-If a merge request is eventually merged to the default branch (in our case
-`master`) and that branch also deploys to an environment (in our case `staging`
-and/or `production`) you can see this information in the merge request itself.
+You can see this information in a merge request itself if:
+
+- The merge request is eventually merged to the default branch (usually `master`).
+- That branch also deploys to an environment (for example, `staging` or `production`).
+
+For example:
![Environment URLs in merge request](img/environments_link_url_mr.png)
-### Go directly from source files to public pages on the environment
+#### Going from source files to public pages
With GitLab's [Route Maps](review_apps/index.md#route-maps) you can go directly
from source files to public pages on the environment set for Review Apps.
-From then on, you have a full development cycle, where your app is tested, built, deployed
-as a Review App, deployed to a staging server once the merge request is merged,
-and finally manually deployed to the production server. This is a simple workflow,
-but when you have multiple developers working on a project
-at the same time, each of them pushing to their own branches, dynamic environments are
-created all the time. In which case, you probably want to do some clean up. Read
-next how environments can be stopped.
+### Stopping an environment
-## Stopping an environment
+Stopping an environment:
-By stopping an environment, you are effectively terminating its recording of the
-deployments that happen in it.
+- Moves it from the list of **Available** environments to the list of **Stopped** environments on the [**Environments** page](#viewing-environments-and-deployments).
+- Executes an [`on_stop` action](yaml/README.md#environmenton_stop), if defined.
-A branch is associated with an environment when the CI pipeline that is created
-for this branch, was recently deployed to this environment. You can think of
-the CI pipeline as the glue between the branch and the environment:
-`branch ➔ CI pipeline ➔ environment`.
+This is often used when multiple developers are working on a project at the same time,
+each of them pushing to their own branches, causing many dynamic environments to be created.
-There is a special case where environments can be manually stopped. That can
-happen if you provide another job for that matter. The syntax is a little
-tricky since a job calls another job to do the job.
+NOTE: **Note:**
+Starting with GitLab 8.14, dynamic environments will be stopped automatically
+when their associated branch is deleted.
+
+#### Automatically stopping an environment
+
+Environments can be stopped automatically using special configuration.
Consider the following example where the `deploy_review` calls the `stop_review`
to clean up and stop the environment:
@@ -470,35 +542,31 @@ stop_review:
action: stop
```
-Setting the [`GIT_STRATEGY`][git-strategy] to `none` is necessary on the
-`stop_review` job so that the [GitLab Runner] won't try to checkout the code
+Setting the [`GIT_STRATEGY`](yaml/README.md#git-strategy) to `none` is necessary on the
+`stop_review` job so that the [GitLab Runner](https://docs.gitlab.com/runner/) won't try to check out the code
after the branch is deleted.
->**Note:**
-Starting with GitLab 8.14, dynamic environments will be stopped automatically
-when their associated branch is deleted.
-
When you have an environment that has a stop action defined (typically when
-the environment describes a review app), GitLab will automatically trigger a
+the environment describes a Review App), GitLab will automatically trigger a
stop action when the associated branch is deleted. The `stop_review` job must
be in the same `stage` as the `deploy_review` one in order for the environment
to automatically stop.
-You can read more in the [`.gitlab-ci.yml` reference][onstop].
+You can read more in the [`.gitlab-ci.yml` reference](yaml/README.md#environmenton_stop).
-## Grouping similar environments
+### Grouping similar environments
-> [Introduced][ce-7015] in GitLab 8.14.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7015) in GitLab 8.14.
-As we've seen in the [dynamic environments](#dynamic-environments), you can
-prepend their name with a word, then followed by a `/` and finally the branch
-name which is automatically defined by the `CI_COMMIT_REF_NAME` variable.
+As documented in [Configuring dynamic environments](#configuring-dynamic-environments), you can
+prepend environment name with a word, followed by a `/`, and finally the branch
+name, which is automatically defined by the `CI_COMMIT_REF_NAME` variable.
In short, environments that are named like `type/foo` are presented under a
group named `type`.
-In our minimal example, we name the environments `review/$CI_COMMIT_REF_NAME`
-where `$CI_COMMIT_REF_NAME` is the branch name:
+In our [minimal example](#example-configuration), we named the environments `review/$CI_COMMIT_REF_NAME`
+where `$CI_COMMIT_REF_NAME` is the branch name. Here is a snippet of the example:
```yaml
deploy_review:
@@ -509,49 +577,47 @@ deploy_review:
name: review/$CI_COMMIT_REF_NAME
```
-In that case, if you visit the Environments page, and provided the branches
+In this case, if you visit the **Environments** page and the branches
exist, you should see something like:
![Environment groups](img/environments_dynamic_groups.png)
-## Monitoring environments
+### Monitoring environments
> **Notes:**
>
> - For the monitoring dashboard to appear, you need to:
-> - Have enabled the [Prometheus integration][prom]
-> - Configured Prometheus to collect at least one [supported metric](../user/project/integrations/prometheus_library/index.md)
-> - With GitLab 9.2, all deployments to an environment are shown directly on the
-> monitoring dashboard
+> - Enable the [Prometheus integration](../user/project/integrations/prometheus.md).
+> - Configure Prometheus to collect at least one [supported metric](../user/project/integrations/prometheus_library/index.md)
+> - With GitLab 9.2, all deployments to an environment are shown directly on the monitoring dashboard.
-If you have enabled [Prometheus for monitoring system and response metrics](https://docs.gitlab.com/ee/user/project/integrations/prometheus.html), you can monitor the performance behavior of your app running in each environment.
+If you have enabled [Prometheus for monitoring system and response metrics](../user/project/integrations/prometheus.md), you can monitor the performance behavior of your app running in each environment.
-Once configured, GitLab will attempt to retrieve [supported performance metrics](https://docs.gitlab.com/ee/user/project/integrations/prometheus_library/index.html) for any
-environment which has had a successful deployment. If monitoring data was
-successfully retrieved, a Monitoring button will appear for each environment.
+Once configured, GitLab will attempt to retrieve [supported performance metrics](../user/project/integrations/prometheus_library/index.md) for any
+environment that has had a successful deployment. If monitoring data was
+successfully retrieved, a **Monitoring** button will appear for each environment.
![Environment Detail with Metrics](img/deployments_view.png)
-Clicking on the Monitoring button will display a new page, showing up to the last
+Clicking on the **Monitoring** button will display a new page showing up to the last
8 hours of performance data. It may take a minute or two for data to appear
after initial deployment.
-All deployments to an environment are shown directly on the monitoring dashboard
+All deployments to an environment are shown directly on the monitoring dashboard,
which allows easy correlation between any changes in performance and a new
version of the app, all without leaving GitLab.
![Monitoring dashboard](img/environments_monitoring.png)
-## Web terminals
+### Web terminals
+
+> Web terminals were added in GitLab 8.15 and are only available to project Maintainers and Owners.
->**Note:**
-Web terminals were added in GitLab 8.15 and are only available to project
-maintainers and owners.
+If you deploy to your environments with the help of a deployment service (for example,
+the [Kubernetes integration](../user/project/clusters/index.md)), GitLab can open
+a terminal session to your environment.
-If you deploy to your environments with the help of a deployment service (e.g.,
-the [Kubernetes integration][kube]), GitLab can open
-a terminal session to your environment! This is a very powerful feature that
-allows you to debug issues without leaving the comfort of your web browser. To
+This is a powerful feature that allows you to debug issues without leaving the comfort of your web browser. To
enable it, just follow the instructions given in the service integration
documentation.
@@ -568,41 +634,71 @@ establish the terminal session:
![Terminal page](img/environments_terminal_page.png)
-This works just like any other terminal - you'll be in the container created
-by your deployment, so you can run shell commands and get responses in real
-time, check the logs, try out configuration or code tweaks, etc. You can open
-multiple terminals to the same environment - they each get their own shell
-session - and even a multiplexer like `screen` or `tmux`!
+This works just like any other terminal. You'll be in the container created
+by your deployment so you can:
->**Note:**
-Container-based deployments often lack basic tools (like an editor), and may
-be stopped or restarted at any time. If this happens, you will lose all your
-changes! Treat this as a debugging tool, not a comprehensive online IDE.
+- Run shell commands and get responses in real time.
+- Check the logs.
+- Try out configuration or code tweaks etc.
----
+You can open multiple terminals to the same environment, they each get their own shell
+session and even a multiplexer like `screen` or `tmux`.
-While this is fine for deploying to some stable environments like staging or
-production, what happens for branches? So far we haven't defined anything
-regarding deployments for branches other than `master`. Dynamic environments
-will help us achieve that.
+NOTE: **Note:**
+Container-based deployments often lack basic tools (like an editor), and may
+be stopped or restarted at any time. If this happens, you will lose all your
+changes. Treat this as a debugging tool, not a comprehensive online IDE.
-## Checkout deployments locally
+### Check out deployments locally
-Since 8.13, a reference in the git repository is saved for each deployment, so
+Since GitLab 8.13, a reference in the Git repository is saved for each deployment, so
knowing the state of your current environments is only a `git fetch` away.
-In your git config, append the `[remote "<your-remote>"]` block with an extra
+In your Git configuration, append the `[remote "<your-remote>"]` block with an extra
fetch line:
-```
+```text
fetch = +refs/environments/*:refs/remotes/origin/environments/*
```
+### Scoping environments with specs **[PREMIUM]**
+
+Some GitLab [Enterprise Edition](https://about.gitlab.com/pricing/) features can behave differently for each
+environment. For example, you can [create a secret variable to be injected only into a production environment](variables/README.md#limiting-environment-scopes-of-variables-premium).
+
+In most cases, these features use the _environment specs_ mechanism, which offers
+an efficient way to implement scoping within each environment group.
+
+Let's say there are four environments:
+
+- `production`
+- `staging`
+- `review/feature-1`
+- `review/feature-2`
+
+Each environment can be matched with the following environment spec:
+
+| Environment Spec | `production` | `staging` | `review/feature-1` | `review/feature-2` |
+|:-----------------|:-------------|:----------|:-------------------|:-------------------|
+| * | Matched | Matched | Matched | Matched |
+| production | Matched | | | |
+| staging | | Matched | | |
+| review/* | | | Matched | Matched |
+| review/feature-1 | | | Matched | |
+
+As you can see, you can use specific matching for selecting a particular environment,
+and also use wildcard matching (`*`) for selecting a particular environment group,
+such as [Review apps](review_apps/index.md) (`review/*`).
+
+NOTE: **Note:**
+The most _specific_ spec takes precedence over the other wildcard matching.
+In this case, `review/feature-1` spec takes precedence over `review/*` and `*` specs.
+
## Limitations
-1. You are limited to use only the [CI predefined variables][variables] in the
- `environment: name`. If you try to re-use variables defined inside `script`
- as part of the environment name, it will not work.
+You are limited to use only the [CI predefined variables](variables/README.md) in the
+`environment: name`. If you try to re-use variables defined inside `script`
+as part of the environment name, it will not work.
## Further reading
@@ -611,18 +707,3 @@ Below are some links you may find interesting:
- [The `.gitlab-ci.yml` definition of environments](yaml/README.md#environment)
- [A blog post on Deployments & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/)
- [Review Apps - Use dynamic environments to deploy your code for every branch](review_apps/index.md)
-
-[Pipelines]: pipelines.md
-[yaml]: yaml/README.md
-[environments]: #environments
-[deployments]: #deployments
-[permissions]: ../user/permissions.md
-[variables]: variables/README.md
-[env-name]: yaml/README.md#environmentname
-[onstop]: yaml/README.md#environmenton_stop
-[ce-7015]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7015
-[gitlab-flow]: ../workflow/gitlab_flow.md
-[gitlab runner]: https://docs.gitlab.com/runner/
-[git-strategy]: yaml/README.md#git-strategy
-[kube]: ../user/project/clusters/index.md
-[prom]: ../user/project/integrations/prometheus.md
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
new file mode 100644
index 00000000000..219af4ced9d
--- /dev/null
+++ b/doc/ci/environments/protected_environments.md
@@ -0,0 +1,48 @@
+# Protected Environments **[PREMIUM]**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6303) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.3.
+
+## Overview
+
+[Environments](../environments.md) can be used for different reasons:
+
+- Some of them are just for testing.
+- Others are for production.
+
+Because deploy jobs can be raised by different users with different roles, it is important that
+specific environments are "protected" to avoid unauthorized people affecting them.
+
+By default, a protected environment does one thing: it ensures that only people
+with the right privileges can deploy to it, thus keeping it safe.
+
+NOTE: **Note**:
+A GitLab admin is always allowed to use environments, even if they are protected.
+
+To protect, update, or unprotect an environment, you need to have at least
+[Maintainer permissions](../../user/permissions.md).
+
+## Protecting environments
+
+To protect an environment:
+
+1. Navigate to your project's **Settings > CI/CD**.
+1. Expand the **Protected Environments** section.
+1. From the **Environment** dropdown menu, select the environment you want to protect.
+1. In the **Allowed to Deploy** dropdown menu, select the role, users, or groups you want to have deploy access.
+ There are some considerations to have in mind:
+ - There are two roles to choose from:
+ - **Maintainers**: will allow access to all maintainers in the project.
+ - **Developers**: will allow access to all maintainers and all developers in the project.
+ - You can only select groups that are associated with the project.
+ - Only users that have at least Developer permission level will appear on
+ the **Allowed to Deploy** dropdown menu.
+1. Click the **Protect** button.
+
+The protected environment will now appear in the list of protected environments.
+
+## Modifying and unprotecting environments
+
+Maintainers can:
+
+- Update existing protected environments at any time by changing the access on **Allowed to deploy** dropdown menu.
+- Unprotect a protected environment by clicking the **Unprotect** button of the environment to unprotect.
diff --git a/doc/ci/introduction/img/gitlab_workflow_example.png b/doc/ci/introduction/img/gitlab_workflow_example.png
deleted file mode 100644
index 94e7753c3b2..00000000000
--- a/doc/ci/introduction/img/gitlab_workflow_example.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/introduction/img/gitlab_workflow_example_11_9.png b/doc/ci/introduction/img/gitlab_workflow_example_11_9.png
new file mode 100644
index 00000000000..204e9c462e5
--- /dev/null
+++ b/doc/ci/introduction/img/gitlab_workflow_example_11_9.png
Binary files differ
diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md
index 1b423a4696e..d505f2ae4ce 100644
--- a/doc/ci/introduction/index.md
+++ b/doc/ci/introduction/index.md
@@ -154,7 +154,7 @@ Once you're happy with your implementation:
- GitLab CI/CD deploys your changes automatically to a production environment.
- And finally, you and your team can easily roll it back if something goes wrong.
-<img src="img/gitlab_workflow_example.png" alt="GitLab workflow example" class="image-noshadow">
+<img src="img/gitlab_workflow_example_11_9.png" alt="GitLab workflow example" class="image-noshadow">
GitLab CI/CD is capable of a doing a lot more, but this workflow
exemplifies GitLab's ability to track the entire process,
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index 9684cb6ed98..65886400c64 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -105,7 +105,7 @@ Jobs are used to create jobs, which are then picked by
What is important is that each job is run independently from each other.
If you want to check whether the `.gitlab-ci.yml` of your project is valid, there is a
-Lint tool under the page `/ci/lint` of your project namespace. You can also find
+Lint tool under the page `/-/ci/lint` of your project namespace. You can also find
a "CI Lint" button to go to this page under **CI/CD ➔ Pipelines** and
**Pipelines ➔ Jobs** in your project.
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 814185f7732..8827961d86c 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -45,10 +45,11 @@ version of [GitLab Runner](https://docs.gitlab.com/runner/) is used. Consult the
version of Runner required.
NOTE: **Note:**
-Starting with GitLab 9.0, we have deprecated some variables. Read the
-[9.0 Renaming](#gitlab-90-renaming) section to find out their replacements. **You are
-strongly advised to use the new variables as we will remove the old ones in
-future GitLab releases.**
+Starting with GitLab 9.0, we have deprecated some variables.
+Read the [deprecated variables](deprecated_variables.md)
+document to find out their replacements. **You are strongly advised
+to use the new variables as we will remove the old ones in future
+GitLab releases.**
| Variable | GitLab | Runner | Description |
|-------------------------------------------|--------|--------|-------------|
@@ -141,32 +142,6 @@ future GitLab releases.**
| **GITLAB_USER_NAME** | 10.0 | all | The real name of the user who started the job |
| **RESTORE_CACHE_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to restore the cache running a job |
-## GitLab 9.0 renaming
-
-To follow conventions of naming across GitLab, and to further move away from the
-`build` term and toward `job` CI variables have been renamed for the 9.0
-release.
-
-NOTE: **Note:**
-Starting with GitLab 9.0, we have deprecated the `$CI_BUILD_*` variables. **You are
-strongly advised to use the new variables as we will remove the old ones in
-future GitLab releases.**
-
-| 8.x name | 9.0+ name |
-| --------------------- |------------------------ |
-| `CI_BUILD_ID` | `CI_JOB_ID` |
-| `CI_BUILD_REF` | `CI_COMMIT_SHA` |
-| `CI_BUILD_TAG` | `CI_COMMIT_TAG` |
-| `CI_BUILD_BEFORE_SHA` | `CI_COMMIT_BEFORE_SHA` |
-| `CI_BUILD_REF_NAME` | `CI_COMMIT_REF_NAME` |
-| `CI_BUILD_REF_SLUG` | `CI_COMMIT_REF_SLUG` |
-| `CI_BUILD_NAME` | `CI_JOB_NAME` |
-| `CI_BUILD_STAGE` | `CI_JOB_STAGE` |
-| `CI_BUILD_REPO` | `CI_REPOSITORY_URL` |
-| `CI_BUILD_TRIGGERED` | `CI_PIPELINE_TRIGGERED` |
-| `CI_BUILD_MANUAL` | `CI_JOB_MANUAL` |
-| `CI_BUILD_TOKEN` | `CI_JOB_TOKEN` |
-
## `.gitlab-ci.yml` defined variables
NOTE **Note:**
diff --git a/doc/ci/variables/deprecated_variables.md b/doc/ci/variables/deprecated_variables.md
new file mode 100644
index 00000000000..2642c9b0eb4
--- /dev/null
+++ b/doc/ci/variables/deprecated_variables.md
@@ -0,0 +1,27 @@
+# Deprecated GitLab CI/CD variables
+
+## GitLab 9.0 renamed variables
+
+To follow conventions of naming across GitLab, and to further move away from the
+`build` term and toward `job`, some [CI/CD environment variables](README.md#predefined-environment-variables) were renamed for GitLab 9.0
+release.
+
+NOTE: **Note:**
+Starting with GitLab 9.0, we have deprecated the `$CI_BUILD_*` variables. **You are
+strongly advised to use the new variables as we will remove the old ones in
+future GitLab releases.**
+
+| 8.x name | 9.0+ name |
+| --------------------- |------------------------ |
+| `CI_BUILD_ID` | `CI_JOB_ID` |
+| `CI_BUILD_REF` | `CI_COMMIT_SHA` |
+| `CI_BUILD_TAG` | `CI_COMMIT_TAG` |
+| `CI_BUILD_BEFORE_SHA` | `CI_COMMIT_BEFORE_SHA` |
+| `CI_BUILD_REF_NAME` | `CI_COMMIT_REF_NAME` |
+| `CI_BUILD_REF_SLUG` | `CI_COMMIT_REF_SLUG` |
+| `CI_BUILD_NAME` | `CI_JOB_NAME` |
+| `CI_BUILD_STAGE` | `CI_JOB_STAGE` |
+| `CI_BUILD_REPO` | `CI_REPOSITORY_URL` |
+| `CI_BUILD_TRIGGERED` | `CI_PIPELINE_TRIGGERED` |
+| `CI_BUILD_MANUAL` | `CI_JOB_MANUAL` |
+| `CI_BUILD_TOKEN` | `CI_JOB_TOKEN` |
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 9eb694a2c64..3e6e89052f8 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -499,9 +499,9 @@ docker build:
- more_scripts/*.{rb,py,sh}
```
-In the scenario above, if you are pushing multiple commits to GitLab to an
-existing branch, GitLab creates and triggers the `docker build` job, provided that
-one of the commits contains changes to either:
+In the scenario above, when pushing multiple commits to GitLab to an existing
+branch, GitLab creates and triggers `docker build` job, provided that one of the
+commits contains changes to either:
- The `Dockerfile` file.
- Any of the files inside `docker/scripts/` directory.
@@ -514,21 +514,20 @@ the section below.
##### Using `changes` with new branches and tags
-If you are pushing a **new** branch or a **new** tag to GitLab, the policy
-always evaluates to true and GitLab will create a job. This feature is not
-connected with merge requests yet, and because GitLab is creating pipelines
-before an user can create a merge request we don't know a target branch at
-this point.
+When pushing a **new** branch or a **new** tag to GitLab, the policy always
+evaluates to true and GitLab will create a job. This feature is not connected
+with merge requests yet and, because GitLab is creating pipelines before a user
+can create a merge request, it is unknown what the target branch is at this point.
##### Using `changes` with `merge_requests`
With [pipelines for merge requests](../merge_request_pipelines/index.md),
-make it possible to define if a job should be created base on files modified
+it is possible to define a job to be created based on files modified
in a merge request.
For example:
-```
+```yaml
docker build service one:
script: docker build -t my-service-one-image:$CI_COMMIT_REF_SLUG .
only:
@@ -539,9 +538,9 @@ docker build service one:
- service-one/**/*
```
-In the scenario above, if you create or update a merge request that changes
-either files in `service-one` folder or `Dockerfile`, GitLab creates and triggers
-the `docker build service one` job.
+In the scenario above, if a merge request is created or updated that changes
+either files in `service-one` directory or the `Dockerfile`, GitLab creates
+and triggers the `docker build service one` job.
### `tags`
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index bfe1ef75914..b39c302453b 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -52,9 +52,12 @@ for audiences of all ages.
If a contributor is no longer actively working on a submitted merge request
we can decide that the merge request will be finished by one of our
[Merge request coaches][team] or close the merge request. We make this decision
-based on how important the change is for our product vision. If a Merge request
+based on how important the change is for our product vision. If a merge request
coach is going to finish the merge request we assign the
-~"coach will finish" label.
+~"coach will finish" label. When a team member picks up a community contribution,
+we credit the original author by adding a changelog entry crediting the author
+and optionally include the original author on at least one of the commits
+within the MR.
## Helping others
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 41a64044c68..c2e05b2d065 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -909,14 +909,15 @@ export default {
- Since we [can't async load a mixin](https://github.com/vuejs/vue-loader/issues/418#issuecomment-254032223) we will use the [`ee_else_ce`](https://docs.gitlab.com/ee/development/ee_features.html#javascript-code-in-assetsjavascripts) alias we already have for webpack.
- This means all the EE specific props, computed properties, methods, etc that are EE only should be in a mixin in the `ee/` folder and we need to create a CE counterpart of the mixin
- ##### Example:
- ```javascript
- import mixin from 'ee_else_ce/path/mixin';
+##### Example:
+```javascript
+import mixin from 'ee_else_ce/path/mixin';
- {
+{
mixins: [mixin]
- }
- ```
+}
+```
+
- Computed Properties/methods and getters only used in the child import still need a counterpart in CE
- For store modules, we will need a CE counterpart too.
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index dd338f6f67d..131e3edf35e 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -126,5 +126,8 @@ are very appreciative of the work done by translators and proofreaders!
your previous translations by [GitLab team members](https://about.gitlab.com/team/)
or [Core team members](https://about.gitlab.com/core-team/) who are fluent in
the language or current proofreaders.
+ - When a request is made for the first proofreader for a lanuguage and there are no [GitLab team members](https://about.gitlab.com/team/)
+ or [Core team members](https://about.gitlab.com/core-team/) who speak the language, we will request links to previous translation work in other communities or projects.
+
[proofreader-src]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/i18n/proofreader.md
diff --git a/doc/development/sql.md b/doc/development/sql.md
index 47519d39e74..edeca7fb298 100644
--- a/doc/development/sql.md
+++ b/doc/development/sql.md
@@ -155,6 +155,21 @@ The _only_ time you should use `pluck` is when you actually need to operate on
the values in Ruby itself (e.g. write them to a file). In almost all other cases
you should ask yourself "Can I not just use a sub-query?".
+In line with our `CodeReuse/ActiveRecord` cop, you should only use forms like
+`pluck(:id)` or `pluck(:user_id)` within model code. In the former case, you can
+use the `ApplicationRecord`-provided `.pluck_primary_key` helper method instead.
+In the latter, you should add a small helper method to the relevant model.
+
+## Inherit from ApplicationRecord
+
+Most models in the GitLab codebase should inherit from `ApplicationRecord`,
+rather than from `ActiveRecord::Base`. This allows helper methods to be easily
+added.
+
+An exception to this rule exists for models created in database migrations. As
+these should be isolated from application code, they should continue to subclass
+from `ActiveRecord::Base`.
+
## Use UNIONs
UNIONs aren't very commonly used in most Rails applications but they're very
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index b9e3e6aea69..fd99b06b863 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -444,13 +444,6 @@ This is an optional step, since many projects do not have a Kubernetes cluster
available. If the [requirements](#requirements) are not met, the job will
silently be skipped.
-CAUTION: **Caution:**
-Your apps should *not* be manipulated outside of Helm (using Kubernetes directly.)
-This can cause confusion with Helm not detecting the change, and subsequent
-deploys with Auto DevOps can undo your changes. Also, if you change something
-and want to undo it by deploying again, Helm may not detect that anything changed
-in the first place, and thus not realize that it needs to re-apply the old config.
-
[Review Apps][review-app] are temporary application environments based on the
branch's code so developers, designers, QA, product managers, and other
reviewers can actually see and interact with code changes as part of the review
@@ -466,6 +459,24 @@ up in the merge request widget for easy discovery. When the branch or tag is del
for example after the merge request is merged, the Review App will automatically
be deleted.
+Review apps are deployed using the
+[auto-deploy-app](https://gitlab.com/charts/auto-deploy-app) chart with
+Helm. The app will be deployed into the [Kubernetes
+namespace](../../user/project/clusters/index.md#deployment-variables)
+for the environment.
+
+Since GitLab 11.4, a [local
+Tiller](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22036) is
+used. Previous versions of GitLab had a Tiller installed in the project
+namespace.
+
+CAUTION: **Caution:**
+Your apps should *not* be manipulated outside of Helm (using Kubernetes directly).
+This can cause confusion with Helm not detecting the change and subsequent
+deploys with Auto DevOps can undo your changes. Also, if you change something
+and want to undo it by deploying again, Helm may not detect that anything changed
+in the first place, and thus not realize that it needs to re-apply the old config.
+
### Auto DAST **[ULTIMATE]**
> Introduced in [GitLab Ultimate][ee] 10.4.
@@ -504,13 +515,6 @@ This is an optional step, since many projects do not have a Kubernetes cluster
available. If the [requirements](#requirements) are not met, the job will
silently be skipped.
-CAUTION: **Caution:**
-Your apps should *not* be manipulated outside of Helm (using Kubernetes directly.)
-This can cause confusion with Helm not detecting the change, and subsequent
-deploys with Auto DevOps can undo your changes. Also, if you change something
-and want to undo it by deploying again, Helm may not detect that anything changed
-in the first place, and thus not realize that it needs to re-apply the old config.
-
After a branch or merge request is merged into the project's default branch (usually
`master`), Auto Deploy deploys the application to a `production` environment in
the Kubernetes cluster, with a namespace based on the project name and unique
@@ -523,6 +527,24 @@ enable them.
You can make use of [environment variables](#environment-variables) to automatically
scale your pod replicas.
+Apps are deployed using the
+[auto-deploy-app](https://gitlab.com/charts/auto-deploy-app) chart with
+Helm. The app will be deployed into the [Kubernetes
+namespace](../../user/project/clusters/index.md#deployment-variables)
+for the environment.
+
+Since GitLab 11.4, a [local
+Tiller](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22036) is
+used. Previous versions of GitLab had a Tiller installed in the project
+namespace.
+
+CAUTION: **Caution:**
+Your apps should *not* be manipulated outside of Helm (using Kubernetes directly).
+This can cause confusion with Helm not detecting the change and subsequent
+deploys with Auto DevOps can undo your changes. Also, if you change something
+and want to undo it by deploying again, Helm may not detect that anything changed
+in the first place, and thus not realize that it needs to re-apply the old config.
+
> [Introduced][ce-19507] in GitLab 11.0.
For internal and private projects a [GitLab Deploy Token](../../user/project/deploy_tokens/index.md#gitlab-deploy-token)
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index 3a4d09c35d9..52b4a72e688 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -5,12 +5,9 @@
Personal access tokens are the preferred way for third party applications and scripts to
authenticate with the [GitLab API][api], if using [OAuth2](../../api/oauth2.md) is not practical.
-You can also use them to authenticate against Git over HTTP. They are the only
-accepted method of authentication when you have
-[Two-Factor Authentication (2FA)][2fa] enabled.
+You can also use personal access tokens to authenticate against Git over HTTP or SSH. They must be used when you have [Two-Factor Authentication (2FA)][2fa] enabled. Authenticate with a token in place of your password.
-Once you have your token, [pass it to the API][usage] using either the
-`private_token` parameter or the `Private-Token` header.
+To make [authenticated requests to the API][usage], use either the `private_token` parameter or the `Private-Token` header.
The expiration of personal access tokens happens on the date you define,
at midnight UTC.
diff --git a/doc/user/project/pipelines/schedules.md b/doc/user/project/pipelines/schedules.md
index 2911a56cf67..89f1beb6d1f 100644
--- a/doc/user/project/pipelines/schedules.md
+++ b/doc/user/project/pipelines/schedules.md
@@ -2,29 +2,33 @@
> **Notes**:
>
-> - This feature was introduced in 9.1 as [Trigger Schedule][ce-10533].
-> - In 9.2, the feature was [renamed to Pipeline Schedule][ce-10853].
+> - Introduced in GitLab 9.1 as [Trigger Schedule](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533).
+> - [Renamed to Pipeline Schedule](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10853) in GitLab 9.2.
> - Cron notation is parsed by [Fugit](https://github.com/floraison/fugit).
-Pipeline schedules can be used to run a pipeline at specific intervals, for example every
-month on the 22nd for a certain branch.
+Pipelines are normally run based on certain conditions being met. For example, when a branch is pushed to repository.
-## Using Pipeline schedules
+Pipeline schedules can be used to also run [pipelines](../../../ci/pipelines.md) at specific intervals. For example:
-In order to schedule a pipeline:
+- Every month on the 22nd for a certain branch.
+- Once every day.
-1. Navigate to your project's **CI / CD ➔ Schedules** and click the
- **New Schedule** button.
-1. Fill in the form
-1. Hit **Save pipeline schedule** for the changes to take effect.
+In addition to using the GitLab UI, pipeline schedules can be maintained using the
+[Pipeline schedules API](../../../api/pipeline_schedules.md).
+
+## Configuring pipeline schedules
+
+To schedule a pipeline for project:
+
+1. Navigate to the project's **CI / CD > Schedules** page.
+1. Click the **New schedule** button.
+1. Fill in the **Schedule a new pipeline** form.
+1. Click the **Save pipeline schedule** button.
![New Schedule Form](img/pipeline_schedules_new_form.png)
-> **Attention:**
-The pipelines won't be executed precisely, because schedules are handled by
-Sidekiq, which runs according to its interval.
-See [advanced admin configuration](#advanced-admin-configuration) for more
-information.
+NOTE: **Note:**
+Pipelines execution [timing is dependent](#advanced-configuration) on Sidekiq's own schedule.
In the **Schedules** index page you can see a list of the pipelines that are
scheduled to run. The next run is automatically calculated by the server GitLab
@@ -32,36 +36,24 @@ is installed on.
![Schedules list](img/pipeline_schedules_list.png)
-### Running a scheduled pipeline manually
-
-> [Introduced][ce-15700] in GitLab 10.4.
-
-To trigger a pipeline schedule manually, click the "Play" button:
-
-![Play Pipeline Schedule](img/pipeline_schedule_play.png)
-
-This will schedule a background job to run the pipeline schedule. A flash
-message will provide a link to the CI/CD Pipeline index page.
-
-To help avoid abuse, users are rate limited to triggering a pipeline once per
-minute.
-
-### Making use of scheduled pipeline variables
+### Using variables
-> [Introduced][ce-12328] in GitLab 9.4.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12328) in GitLab 9.4.
You can pass any number of arbitrary variables and they will be available in
-GitLab CI so that they can be used in your `.gitlab-ci.yml` file.
+GitLab CI so that they can be used in your [`.gitlab-ci.yml` file](../../../ci/yaml/README.md).
![Scheduled pipeline variables](img/pipeline_schedule_variables.png)
-## Using only and except
+### Using only and except
To configure that a job can be executed only when the pipeline has been
scheduled (or the opposite), you can use
[only and except](../../../ci/yaml/README.md#onlyexcept-basic) configuration keywords.
-```
+For example:
+
+```yaml
job:on-schedule:
only:
- schedules
@@ -75,11 +67,47 @@ job:
- make build
```
-## Taking ownership
+### Advanced configuration
+
+The pipelines won't be executed exactly on schedule because schedules are handled by
+Sidekiq, which runs according to its interval.
+
+For example, only two pipelines will be created per day if:
-Pipelines are executed as a user, who owns a schedule. This influences what
-projects and other resources the pipeline has access to. If a user does not own
-a pipeline, you can take ownership by clicking the **Take ownership** button.
+- You set a schedule to create a pipeline every minute (`* * * * *`).
+- The Sidekiq worker runs on 00:00 and 12:00 every day (`0 */12 * * *`).
+
+To change the Sidekiq worker's frequency:
+
+1. Edit the `pipeline_schedule_worker_cron` value in your instance's `gitlab.rb` file.
+1. [Restart GitLab](../../../administration/restart_gitlab.md).
+
+For GitLab.com, refer to the [dedicated settings page](../../gitlab_com/index.md#cron-jobs).
+
+## Working with scheduled pipelines
+
+Once configured, GitLab supports many functions for working with scheduled pipelines.
+
+### Running manually
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15700) in GitLab 10.4.
+
+To trigger a pipeline schedule manually, click the "Play" button:
+
+![Play Pipeline Schedule](img/pipeline_schedule_play.png)
+
+This will schedule a background job to run the pipeline schedule. A flash
+message will provide a link to the CI/CD Pipeline index page.
+
+NOTE: **Note:**
+To help avoid abuse, users are rate limited to triggering a pipeline once per
+minute.
+
+### Taking ownership
+
+Pipelines are executed as a user, who owns a schedule. This influences what projects and other resources the pipeline has access to.
+
+If a user does not own a pipeline, you can take ownership by clicking the **Take ownership** button.
The next time a pipeline is scheduled, your credentials will be used.
![Schedules list](img/pipeline_schedules_ownership.png)
@@ -90,20 +118,3 @@ on the target branch, the schedule will stop creating new pipelines. This can
happen if, for example, the owner is blocked or removed from the project, or
the target branch or tag is protected. In this case, someone with sufficient
privileges must take ownership of the schedule.
-
-## Advanced admin configuration
-
-The pipelines won't be executed precisely, because schedules are handled by
-Sidekiq, which runs according to its interval. For example, if you set a
-schedule to create a pipeline every minute (`* * * * *`) and the Sidekiq worker
-runs on 00:00 and 12:00 every day (`0 */12 * * *`), only 2 pipelines will be
-created per day. To change the Sidekiq worker's frequency, you have to edit the
-`pipeline_schedule_worker_cron` value in your `gitlab.rb` and restart GitLab.
-For GitLab.com, you can check the [dedicated settings page][settings]. If you
-don't have admin access to the server, ask your administrator.
-
-[ce-10533]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533
-[ce-10853]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10853
-[ce-12328]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12328
-[ce-15700]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15700
-[settings]: https://about.gitlab.com/gitlab-com/settings/#cron-jobs
diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md
index 3fb553280d0..6d941135bf2 100644
--- a/doc/workflow/lfs/lfs_administration.md
+++ b/doc/workflow/lfs/lfs_administration.md
@@ -108,6 +108,18 @@ Here is a configuration example with GCS.
_NOTE: The service account must have permission to access the bucket. [See more](https://cloud.google.com/storage/docs/authentication)_
+Here is a configuration example with Rackspace Cloud Files.
+
+| Setting | Description | example |
+|---------|-------------|---------|
+| `provider` | The provider name | `Rackspace` |
+| `rackspace_username` | The username of the Rackspace account with access to the container | `joe.smith` |
+| `rackspace_api_key` | The API key of the Rackspace account with access to the container | `ABC123DEF456ABC123DEF456ABC123DE` |
+| `rackspace_region` | The Rackspace storage region to use, a three letter code from the [list of service access endpoints](https://developer.rackspace.com/docs/cloud-files/v1/general-api-info/service-access/) | `iad` |
+| `rackspace_temp_url_key` | The private key you have set in the Rackspace API for temporary URLs. Read more [here](https://developer.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl) | `ABC123DEF456ABC123DEF456ABC123DE` |
+
+_NOTES: Regardless of whether the container has public access enabled or disabled, Fog will use the TempURL method to grant access to LFS objects. If you see errors in logs referencing instantiating storage with a temp-url-key, ensure that you have set they key properly on the Rackspace API and in gitlab.rb. You can verify the value of the key Rackspace has set by sending a GET request with token header to the service access endpoint URL and comparing the output of the returned headers._
+
### Manual uploading to an object storage
There are two ways to manually do the same thing as automatic uploading (described above).
diff --git a/jest.config.js b/jest.config.js
index cd0d311779d..c7518be9e96 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,4 +1,4 @@
-/* eslint-disable filenames/match-regex */
+const IS_EE = require('./config/helpers/is_ee_env');
const reporters = ['default'];
@@ -38,4 +38,7 @@ module.exports = {
transformIgnorePatterns: ['node_modules/(?!(@gitlab/ui)/)'],
timers: 'fake',
testEnvironment: '<rootDir>/spec/frontend/environment.js',
+ testEnvironmentOptions: {
+ IS_EE,
+ },
};
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 07f529b01bb..5c98b0ad56c 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -34,11 +34,11 @@ module API
repository = user_project.repository
branches = BranchesFinder.new(repository, declared_params(include_missing: false)).execute
- branches = ::Kaminari.paginate_array(branches)
+ branches = paginate(::Kaminari.paginate_array(branches))
merged_branch_names = repository.merged_branch_names(branches.map(&:name))
present(
- paginate(branches),
+ branches,
with: Entities::Branch,
current_user: current_user,
project: user_project,
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 0871ea8d21e..4533305bfd3 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1588,7 +1588,7 @@ module API
end
class Cluster < Grape::Entity
- expose :id, :name, :created_at
+ expose :id, :name, :created_at, :domain
expose :provider_type, :platform_type, :environment_scope, :cluster_type
expose :user, using: Entities::UserBasic
expose :platform_kubernetes, using: Entities::Platform::Kubernetes
diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb
index c96261a7b57..b62ec887183 100644
--- a/lib/api/project_clusters.rb
+++ b/lib/api/project_clusters.rb
@@ -53,6 +53,7 @@ module API
params do
requires :name, type: String, desc: 'Cluster name'
optional :enabled, type: Boolean, default: true, desc: 'Determines if cluster is active or not, defaults to true'
+ optional :domain, type: String, desc: 'Cluster base domain'
requires :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
requires :api_url, type: String, allow_blank: false, desc: 'URL to access the Kubernetes API'
requires :token, type: String, desc: 'Token to authenticate against Kubernetes'
@@ -83,6 +84,7 @@ module API
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
optional :name, type: String, desc: 'Cluster name'
+ optional :domain, type: String, desc: 'Cluster base domain'
optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
optional :token, type: String, desc: 'Token to authenticate against Kubernetes'
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index f42ca5a9cd6..1204e53ee2e 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -24,7 +24,7 @@ module Gitlab
if File.exist?(root.join("REVISION"))
File.read(root.join("REVISION")).strip.freeze
else
- result = Gitlab::Popen.popen_with_detail(%W[#{config.git.bin_path} log --pretty=format:%h -n 1])
+ result = Gitlab::Popen.popen_with_detail(%W[#{config.git.bin_path} log --pretty=format:%h --abbrev=11 -n 1])
if result.status.success?
result.stdout.chomp.freeze
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index bf9f03f6134..03af99ba9a5 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -33,6 +33,13 @@ module Gitlab
end
end
+ def merge_request_ref_exists?
+ strong_memoize(:merge_request_ref_exists) do
+ MergeRequest.merge_request_ref?(origin_ref) &&
+ project.repository.ref_exists?(origin_ref)
+ end
+ end
+
def ref
strong_memoize(:ref) do
Gitlab::Git.ref_name(origin_ref)
diff --git a/lib/gitlab/ci/pipeline/chain/validate/abilities.rb b/lib/gitlab/ci/pipeline/chain/validate/abilities.rb
index ebd7e6e8289..aaa3daddcc5 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/abilities.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/abilities.rb
@@ -44,6 +44,8 @@ module Gitlab
access.can_update_branch?(@command.ref)
elsif @command.tag_exists?
access.can_create_tag?(@command.ref)
+ elsif @command.merge_request_ref_exists?
+ access.can_update_branch?(@command.merge_request.source_branch)
else
true # Allow it for now and we'll reject when we check ref existence
end
diff --git a/lib/gitlab/ci/pipeline/chain/validate/repository.rb b/lib/gitlab/ci/pipeline/chain/validate/repository.rb
index 9c6c2bc8e25..8f5445850d7 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/repository.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/repository.rb
@@ -9,7 +9,7 @@ module Gitlab
include Chain::Helpers
def perform!
- unless @command.branch_exists? || @command.tag_exists?
+ unless @command.branch_exists? || @command.tag_exists? || @command.merge_request_ref_exists?
return error('Reference not found')
end
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 78872b3bbe3..3116f1a136b 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -531,8 +531,8 @@ rollout 100%:
touch clair-whitelist.yml
retries=0
echo "Waiting for clair daemon to start"
- while( ! wget -T 10 -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
- ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
+ while( ! wget -T 10 -q -O /dev/null http://${DOCKER_SERVICE}:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
+ ./clair-scanner -c http://${DOCKER_SERVICE}:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
}
function code_quality() {
@@ -800,10 +800,15 @@ rollout 100%:
kubectl version --client
}
+ # With the Kubernetes executor, 'localhost' must be used instead
+ # https://docs.gitlab.com/runner/executors/kubernetes.html
function setup_docker() {
if ! docker info &>/dev/null; then
if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then
export DOCKER_HOST='tcp://localhost:2375'
+ export DOCKER_SERVICE="localhost"
+ else
+ export DOCKER_SERVICE="docker"
fi
fi
}
diff --git a/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
index ea1e6ae5fdc..0b7a531682b 100644
--- a/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
@@ -17,23 +17,30 @@ container_scanning:
#
# Container Scanning deals with Docker images only so no need to import the project's Git repository:
GIT_STRATEGY: none
+ # Services and containers running in the same Kubernetes pod are all sharing the same localhost address
+ # https://docs.gitlab.com/runner/executors/kubernetes.html
+ DOCKER_SERVICE: docker
+ DOCKER_HOST: tcp://${DOCKER_SERVICE}:2375/
+ # https://hub.docker.com/r/arminc/clair-local-scan/tags
+ CLAIR_LOCAL_SCAN_VERSION: v2.0.6
allow_failure: true
services:
- docker:stable-dind
script:
+ - if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then { export DOCKER_SERVICE="localhost" ; export DOCKER_HOST="tcp://${DOCKER_SERVICE}:2375" ; } fi
- docker run -d --name db arminc/clair-db:latest
- - docker run -p 6060:6060 --link db:postgres -d --name clair --restart on-failure arminc/clair-local-scan:v2.0.6
+ - docker run -p 6060:6060 --link db:postgres -d --name clair --restart on-failure arminc/clair-local-scan:${CLAIR_LOCAL_SCAN_VERSION}
- apk add -U wget ca-certificates
- docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG}
- wget https://github.com/arminc/clair-scanner/releases/download/v8/clair-scanner_linux_amd64
- mv clair-scanner_linux_amd64 clair-scanner
- chmod +x clair-scanner
- touch clair-whitelist.yml
- - while( ! wget -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; done
+ - while( ! wget -q -O /dev/null http://${DOCKER_SERVICE}:6060/v1/namespaces ) ; do sleep 1 ; done
- retries=0
- echo "Waiting for clair daemon to start"
- - while( ! wget -T 10 -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
- - ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
+ - while( ! wget -T 10 -q -O /dev/null http://${DOCKER_SERVICE}:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
+ - ./clair-scanner -c http://${DOCKER_SERVICE}:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 552aad83dd4..469a7fd9f7b 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -47,7 +47,7 @@ module Gitlab
# defaults for missing columns.
if ActiveRecord::Migrator.needs_migration?
db_attributes = current_settings&.attributes || {}
- ::ApplicationSetting.build_from_defaults(db_attributes)
+ fake_application_settings(db_attributes)
elsif current_settings.present?
current_settings
else
diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb
index a4a154c80f7..5a61a7f5d60 100644
--- a/lib/gitlab/encoding_helper.rb
+++ b/lib/gitlab/encoding_helper.rb
@@ -76,8 +76,11 @@ module Gitlab
str.dup.force_encoding(Encoding::ASCII_8BIT)
end
- def binary_stringio(str)
- StringIO.new(str.freeze || '').tap { |io| io.set_encoding(Encoding::ASCII_8BIT) }
+ def binary_io(str_or_io)
+ io = str_or_io.to_io.dup if str_or_io.respond_to?(:to_io)
+ io ||= StringIO.new(str_or_io.to_s.freeze)
+
+ io.tap { |io| io.set_encoding(Encoding::ASCII_8BIT) }
end
private
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 49cff7517e9..35565b68388 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -232,7 +232,7 @@ module Gitlab
result
end
- SERVER_FEATURE_FLAGS = %w[go-find-all-tags].freeze
+ SERVER_FEATURE_FLAGS = %w[].freeze
def self.server_feature_flags
SERVER_FEATURE_FLAGS.map do |f|
@@ -302,6 +302,26 @@ module Gitlab
end
end
+ # Normally a FindCommit RPC will cache the commit with its SHA
+ # instead of a ref name, since it's possible the branch is mutated
+ # afterwards. However, for read-only requests that never mutate the
+ # branch, this method allows caching of the ref name directly.
+ def self.allow_ref_name_caching
+ return yield unless Gitlab::SafeRequestStore.active?
+ return yield if ref_name_caching_allowed?
+
+ begin
+ Gitlab::SafeRequestStore[:allow_ref_name_caching] = true
+ yield
+ ensure
+ Gitlab::SafeRequestStore[:allow_ref_name_caching] = false
+ end
+ end
+
+ def self.ref_name_caching_allowed?
+ Gitlab::SafeRequestStore[:allow_ref_name_caching]
+ end
+
def self.get_call_count(key)
Gitlab::SafeRequestStore[key] || 0
end
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index ea12424eb4a..0d5debfcd01 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -286,7 +286,7 @@ module Gitlab
commit = call_find_commit(revision)
return unless commit
- key[:commit_id] = commit.id
+ key[:commit_id] = commit.id unless GitalyClient.ref_name_caching_allowed?
Gitlab::SafeRequestStore[key] = commit
else
call_find_commit(revision)
diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb
index 6304f998563..077b63205a8 100644
--- a/lib/gitlab/gitaly_client/conflicts_service.rb
+++ b/lib/gitlab/gitaly_client/conflicts_service.rb
@@ -37,7 +37,7 @@ module Gitlab
end
def resolve_conflicts(target_repository, resolution, source_branch, target_branch)
- reader = binary_stringio(resolution.files.to_json)
+ reader = binary_io(resolution.files.to_json)
req_enum = Enumerator.new do |y|
header = resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch)
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index 2528208440e..b0f328ce3d4 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -294,7 +294,7 @@ module Gitlab
action: Gitaly::UserCommitFilesAction.new(header: action_header)
)
- reader = binary_stringio(action[:content])
+ reader = binary_io(action[:content])
until reader.eof?
chunk = reader.read(MAX_MSG_SIZE)
@@ -327,7 +327,7 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
target_branch: encode_binary(branch_name)
)
- reader = binary_stringio(patches)
+ reader = binary_io(patches)
chunks = Enumerator.new do |chunk|
chunk.yield Gitaly::UserApplyPatchRequest.new(header: header)
diff --git a/lib/gitlab/gitaly_client/wiki_service.rb b/lib/gitlab/gitaly_client/wiki_service.rb
index 2b3d622af4d..15c9463e2f2 100644
--- a/lib/gitlab/gitaly_client/wiki_service.rb
+++ b/lib/gitlab/gitaly_client/wiki_service.rb
@@ -22,7 +22,7 @@ module Gitlab
commit_details: gitaly_commit_details(commit_details)
)
- strio = binary_stringio(content)
+ strio = binary_io(content)
enum = Enumerator.new do |y|
until strio.eof?
@@ -49,7 +49,7 @@ module Gitlab
commit_details: gitaly_commit_details(commit_details)
)
- strio = binary_stringio(content)
+ strio = binary_io(content)
enum = Enumerator.new do |y|
until strio.eof?
diff --git a/lib/gitlab/quick_actions/command_definition.rb b/lib/gitlab/quick_actions/command_definition.rb
index e7bfcb16582..93030fd454e 100644
--- a/lib/gitlab/quick_actions/command_definition.rb
+++ b/lib/gitlab/quick_actions/command_definition.rb
@@ -4,7 +4,7 @@ module Gitlab
module QuickActions
class CommandDefinition
attr_accessor :name, :aliases, :description, :explanation, :params,
- :condition_block, :parse_params_block, :action_block, :warning
+ :condition_block, :parse_params_block, :action_block, :warning, :types
def initialize(name, attributes = {})
@name = name
@@ -17,6 +17,7 @@ module Gitlab
@condition_block = attributes[:condition_block]
@parse_params_block = attributes[:parse_params_block]
@action_block = attributes[:action_block]
+ @types = attributes[:types] || []
end
def all_names
@@ -28,6 +29,7 @@ module Gitlab
end
def available?(context)
+ return false unless valid_type?(context)
return true unless condition_block
context.instance_exec(&condition_block)
@@ -96,6 +98,10 @@ module Gitlab
context.instance_exec(arg, &parse_params_block)
end
+
+ def valid_type?(context)
+ types.blank? || types.any? { |type| context.quick_action_target.is_a?(type) }
+ end
end
end
end
diff --git a/lib/gitlab/quick_actions/commit_actions.rb b/lib/gitlab/quick_actions/commit_actions.rb
new file mode 100644
index 00000000000..62c0fbb5afd
--- /dev/null
+++ b/lib/gitlab/quick_actions/commit_actions.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module QuickActions
+ module CommitActions
+ extend ActiveSupport::Concern
+ include Gitlab::QuickActions::Dsl
+
+ included do
+ # Commit only quick actions definitions
+ desc 'Tag this commit.'
+ explanation do |tag_name, message|
+ with_message = %{ with "#{message}"} if message.present?
+ "Tags this commit to #{tag_name}#{with_message}."
+ end
+ params 'v1.2.3 <message>'
+ parse_params do |tag_name_and_message|
+ tag_name_and_message.split(' ', 2)
+ end
+ types Commit
+ condition do
+ current_user.can?(:push_code, project)
+ end
+ command :tag do |tag_name, message|
+ @updates[:tag_name] = tag_name
+ @updates[:tag_message] = message
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/quick_actions/common_actions.rb b/lib/gitlab/quick_actions/common_actions.rb
new file mode 100644
index 00000000000..5d2732d4826
--- /dev/null
+++ b/lib/gitlab/quick_actions/common_actions.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module QuickActions
+ module CommonActions
+ extend ActiveSupport::Concern
+ include Gitlab::QuickActions::Dsl
+
+ included do
+ # This is a dummy command, so that it appears in the autocomplete commands
+ desc 'CC'
+ params '@user'
+ command :cc
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/quick_actions/dsl.rb b/lib/gitlab/quick_actions/dsl.rb
index a3aab92061b..ecb2169151e 100644
--- a/lib/gitlab/quick_actions/dsl.rb
+++ b/lib/gitlab/quick_actions/dsl.rb
@@ -24,7 +24,7 @@ module Gitlab
# Example:
#
# desc do
- # "This is a dynamic description for #{noteable.to_ability_name}"
+ # "This is a dynamic description for #{quick_action_target.to_ability_name}"
# end
# command :command_key do |arguments|
# # Awesome code block
@@ -66,6 +66,23 @@ module Gitlab
@explanation = block_given? ? block : text
end
+ # Allows to define type(s) that must be met in order for the command
+ # to be returned by `.command_names` & `.command_definitions`.
+ #
+ # It is being evaluated before the conditions block is being evaluated
+ #
+ # If no types are passed then any type is allowed as the check is simply skipped.
+ #
+ # Example:
+ #
+ # types Commit, Issue, MergeRequest
+ # command :command_key do |arguments|
+ # # Awesome code block
+ # end
+ def types(*types_list)
+ @types = types_list
+ end
+
# Allows to define conditions that must be met in order for the command
# to be returned by `.command_names` & `.command_definitions`.
# It accepts a block that will be evaluated with the context
@@ -144,7 +161,8 @@ module Gitlab
params: @params,
condition_block: @condition_block,
parse_params_block: @parse_params_block,
- action_block: block
+ action_block: block,
+ types: @types
)
self.command_definitions << definition
@@ -159,6 +177,7 @@ module Gitlab
@condition_block = nil
@warning = nil
@parse_params_block = nil
+ @types = nil
end
end
end
diff --git a/lib/gitlab/quick_actions/issuable_actions.rb b/lib/gitlab/quick_actions/issuable_actions.rb
new file mode 100644
index 00000000000..ad2e15d19fa
--- /dev/null
+++ b/lib/gitlab/quick_actions/issuable_actions.rb
@@ -0,0 +1,221 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module QuickActions
+ module IssuableActions
+ extend ActiveSupport::Concern
+ include Gitlab::QuickActions::Dsl
+
+ SHRUG = '¯\\_(ツ)_/¯'.freeze
+ TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
+
+ included do
+ # Issue, MergeRequest, Epic: quick actions definitions
+ desc do
+ "Close this #{quick_action_target.to_ability_name.humanize(capitalize: false)}"
+ end
+ explanation do
+ "Closes this #{quick_action_target.to_ability_name.humanize(capitalize: false)}."
+ end
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.open? &&
+ current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ command :close do
+ @updates[:state_event] = 'close'
+ end
+
+ desc do
+ "Reopen this #{quick_action_target.to_ability_name.humanize(capitalize: false)}"
+ end
+ explanation do
+ "Reopens this #{quick_action_target.to_ability_name.humanize(capitalize: false)}."
+ end
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.closed? &&
+ current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ command :reopen do
+ @updates[:state_event] = 'reopen'
+ end
+
+ desc 'Change title'
+ explanation do |title_param|
+ "Changes the title to \"#{title_param}\"."
+ end
+ params '<New title>'
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ command :title do |title_param|
+ @updates[:title] = title_param
+ end
+
+ desc 'Add label(s)'
+ explanation do |labels_param|
+ labels = find_label_references(labels_param)
+
+ "Adds #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any?
+ end
+ params '~label1 ~"label 2"'
+ types Issuable
+ condition do
+ parent &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", parent) &&
+ find_labels.any?
+ end
+ command :label do |labels_param|
+ label_ids = find_label_ids(labels_param)
+
+ if label_ids.any?
+ @updates[:add_label_ids] ||= []
+ @updates[:add_label_ids] += label_ids
+
+ @updates[:add_label_ids].uniq!
+ end
+ end
+
+ desc 'Remove all or specific label(s)'
+ explanation do |labels_param = nil|
+ if labels_param.present?
+ labels = find_label_references(labels_param)
+ "Removes #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any?
+ else
+ 'Removes all labels.'
+ end
+ end
+ params '~label1 ~"label 2"'
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.labels.any? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", parent)
+ end
+ command :unlabel do |labels_param = nil|
+ if labels_param.present?
+ label_ids = find_label_ids(labels_param)
+
+ if label_ids.any?
+ @updates[:remove_label_ids] ||= []
+ @updates[:remove_label_ids] += label_ids
+
+ @updates[:remove_label_ids].uniq!
+ end
+ else
+ @updates[:label_ids] = []
+ end
+ end
+
+ desc 'Replace all label(s)'
+ explanation do |labels_param|
+ labels = find_label_references(labels_param)
+ "Replaces all labels with #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any?
+ end
+ params '~label1 ~"label 2"'
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.labels.any? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", parent)
+ end
+ command :relabel do |labels_param|
+ label_ids = find_label_ids(labels_param)
+
+ if label_ids.any?
+ @updates[:label_ids] ||= []
+ @updates[:label_ids] += label_ids
+
+ @updates[:label_ids].uniq!
+ end
+ end
+
+ desc 'Add a todo'
+ explanation 'Adds a todo.'
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ !TodoService.new.todo_exist?(quick_action_target, current_user)
+ end
+ command :todo do
+ @updates[:todo_event] = 'add'
+ end
+
+ desc 'Mark todo as done'
+ explanation 'Marks todo as done.'
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ TodoService.new.todo_exist?(quick_action_target, current_user)
+ end
+ command :done do
+ @updates[:todo_event] = 'done'
+ end
+
+ desc 'Subscribe'
+ explanation do
+ "Subscribes to this #{quick_action_target.to_ability_name.humanize(capitalize: false)}."
+ end
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ !quick_action_target.subscribed?(current_user, project)
+ end
+ command :subscribe do
+ @updates[:subscription_event] = 'subscribe'
+ end
+
+ desc 'Unsubscribe'
+ explanation do
+ "Unsubscribes from this #{quick_action_target.to_ability_name.humanize(capitalize: false)}."
+ end
+ types Issuable
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.subscribed?(current_user, project)
+ end
+ command :unsubscribe do
+ @updates[:subscription_event] = 'unsubscribe'
+ end
+
+ desc 'Toggle emoji award'
+ explanation do |name|
+ "Toggles :#{name}: emoji award." if name
+ end
+ params ':emoji:'
+ types Issuable
+ condition do
+ quick_action_target.persisted?
+ end
+ parse_params do |emoji_param|
+ match = emoji_param.match(Banzai::Filter::EmojiFilter.emoji_pattern)
+ match[1] if match
+ end
+ command :award do |name|
+ if name && quick_action_target.user_can_award?(current_user)
+ @updates[:emoji_award] = name
+ end
+ end
+
+ desc "Append the comment with #{SHRUG}"
+ params '<Comment>'
+ types Issuable
+ substitution :shrug do |comment|
+ "#{comment} #{SHRUG}"
+ end
+
+ desc "Append the comment with #{TABLEFLIP}"
+ params '<Comment>'
+ types Issuable
+ substitution :tableflip do |comment|
+ "#{comment} #{TABLEFLIP}"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb
new file mode 100644
index 00000000000..1f08e8740a2
--- /dev/null
+++ b/lib/gitlab/quick_actions/issue_actions.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module QuickActions
+ module IssueActions
+ extend ActiveSupport::Concern
+ include Gitlab::QuickActions::Dsl
+
+ included do
+ # Issue only quick actions definition
+ desc 'Set due date'
+ explanation do |due_date|
+ "Sets the due date to #{due_date.to_s(:medium)}." if due_date
+ end
+ params '<in 2 days | this Friday | December 31st>'
+ types Issue
+ condition do
+ quick_action_target.respond_to?(:due_date) &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ parse_params do |due_date_param|
+ Chronic.parse(due_date_param).try(:to_date)
+ end
+ command :due do |due_date|
+ @updates[:due_date] = due_date if due_date
+ end
+
+ desc 'Remove due date'
+ explanation 'Removes the due date.'
+ types Issue
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.respond_to?(:due_date) &&
+ quick_action_target.due_date? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ command :remove_due_date do
+ @updates[:due_date] = nil
+ end
+
+ desc 'Move issue from one column of the board to another'
+ explanation do |target_list_name|
+ label = find_label_references(target_list_name).first
+ "Moves issue to #{label} column in the board." if label
+ end
+ params '~"Target column"'
+ types Issue
+ condition do
+ current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target) &&
+ quick_action_target.project.boards.count == 1
+ end
+ # rubocop: disable CodeReuse/ActiveRecord
+ command :board_move do |target_list_name|
+ label_ids = find_label_ids(target_list_name)
+
+ if label_ids.size == 1
+ label_id = label_ids.first
+
+ # Ensure this label corresponds to a list on the board
+ next unless Label.on_project_boards(quick_action_target.project_id).where(id: label_id).exists?
+
+ @updates[:remove_label_ids] =
+ quick_action_target.labels.on_project_boards(quick_action_target.project_id).where.not(id: label_id).pluck(:id)
+ @updates[:add_label_ids] = [label_id]
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ desc 'Mark this issue as a duplicate of another issue'
+ explanation do |duplicate_reference|
+ "Marks this issue as a duplicate of #{duplicate_reference}."
+ end
+ params '#issue'
+ types Issue
+ condition do
+ quick_action_target.persisted? &&
+ current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ command :duplicate do |duplicate_param|
+ canonical_issue = extract_references(duplicate_param, :issue).first
+
+ if canonical_issue.present?
+ @updates[:canonical_issue_id] = canonical_issue.id
+ end
+ end
+
+ desc 'Move this issue to another project.'
+ explanation do |path_to_project|
+ "Moves this issue to #{path_to_project}."
+ end
+ params 'path/to/project'
+ types Issue
+ condition do
+ quick_action_target.persisted? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ command :move do |target_project_path|
+ target_project = Project.find_by_full_path(target_project_path)
+
+ if target_project.present?
+ @updates[:target_project] = target_project
+ end
+ end
+
+ desc 'Make issue confidential.'
+ explanation do
+ 'Makes this issue confidential'
+ end
+ types Issue
+ condition do
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ command :confidential do
+ @updates[:confidential] = true
+ end
+
+ desc 'Create a merge request.'
+ explanation do |branch_name = nil|
+ branch_text = branch_name ? "branch '#{branch_name}'" : 'a branch'
+ "Creates #{branch_text} and a merge request to resolve this issue"
+ end
+ params "<branch name>"
+ types Issue
+ condition do
+ current_user.can?(:create_merge_request_in, project) && current_user.can?(:push_code, project)
+ end
+ command :create_merge_request do |branch_name = nil|
+ @updates[:create_merge_request] = {
+ branch_name: branch_name,
+ issue_iid: quick_action_target.iid
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
new file mode 100644
index 00000000000..08872eda410
--- /dev/null
+++ b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
@@ -0,0 +1,225 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module QuickActions
+ module IssueAndMergeRequestActions
+ extend ActiveSupport::Concern
+ include Gitlab::QuickActions::Dsl
+
+ included do
+ # Issue, MergeRequest: quick actions definitions
+ desc 'Assign'
+ # rubocop: disable CodeReuse/ActiveRecord
+ explanation do |users|
+ users = quick_action_target.allows_multiple_assignees? ? users : users.take(1)
+ "Assigns #{users.map(&:to_reference).to_sentence}."
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ params do
+ quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : '@user'
+ end
+ types Issue, MergeRequest
+ condition do
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ parse_params do |assignee_param|
+ extract_users(assignee_param)
+ end
+ command :assign do |users|
+ next if users.empty?
+
+ if quick_action_target.allows_multiple_assignees?
+ @updates[:assignee_ids] ||= quick_action_target.assignees.map(&:id)
+ @updates[:assignee_ids] += users.map(&:id)
+ else
+ @updates[:assignee_ids] = [users.first.id]
+ end
+ end
+
+ desc do
+ if quick_action_target.allows_multiple_assignees?
+ 'Remove all or specific assignee(s)'
+ else
+ 'Remove assignee'
+ end
+ end
+ explanation do |users = nil|
+ assignees = quick_action_target.assignees
+ assignees &= users if users.present? && quick_action_target.allows_multiple_assignees?
+ "Removes #{'assignee'.pluralize(assignees.size)} #{assignees.map(&:to_reference).to_sentence}."
+ end
+ params do
+ quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : ''
+ end
+ types Issue, MergeRequest
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.assignees.any? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ parse_params do |unassign_param|
+ # When multiple users are assigned, all will be unassigned if multiple assignees are no longer allowed
+ extract_users(unassign_param) if quick_action_target.allows_multiple_assignees?
+ end
+ command :unassign do |users = nil|
+ if quick_action_target.allows_multiple_assignees? && users&.any?
+ @updates[:assignee_ids] ||= quick_action_target.assignees.map(&:id)
+ @updates[:assignee_ids] -= users.map(&:id)
+ else
+ @updates[:assignee_ids] = []
+ end
+ end
+
+ desc 'Set milestone'
+ explanation do |milestone|
+ "Sets the milestone to #{milestone.to_reference}." if milestone
+ end
+ params '%"milestone"'
+ types Issue, MergeRequest
+ condition do
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project) &&
+ find_milestones(project, state: 'active').any?
+ end
+ parse_params do |milestone_param|
+ extract_references(milestone_param, :milestone).first ||
+ find_milestones(project, title: milestone_param.strip).first
+ end
+ command :milestone do |milestone|
+ @updates[:milestone_id] = milestone.id if milestone
+ end
+
+ desc 'Remove milestone'
+ explanation do
+ "Removes #{quick_action_target.milestone.to_reference(format: :name)} milestone."
+ end
+ types Issue, MergeRequest
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.milestone_id? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ command :remove_milestone do
+ @updates[:milestone_id] = nil
+ end
+
+ desc 'Copy labels and milestone from other issue or merge request'
+ explanation do |source_issuable|
+ "Copy labels and milestone from #{source_issuable.to_reference}."
+ end
+ params '#issue | !merge_request'
+ types Issue, MergeRequest
+ condition do
+ current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ parse_params do |issuable_param|
+ extract_references(issuable_param, :issue).first ||
+ extract_references(issuable_param, :merge_request).first
+ end
+ command :copy_metadata do |source_issuable|
+ if source_issuable.present? && source_issuable.project.id == quick_action_target.project.id
+ @updates[:add_label_ids] = source_issuable.labels.map(&:id)
+ @updates[:milestone_id] = source_issuable.milestone.id if source_issuable.milestone
+ end
+ end
+
+ desc 'Set time estimate'
+ explanation do |time_estimate|
+ time_estimate = Gitlab::TimeTrackingFormatter.output(time_estimate)
+
+ "Sets time estimate to #{time_estimate}." if time_estimate
+ end
+ params '<1w 3d 2h 14m>'
+ types Issue, MergeRequest
+ condition do
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ parse_params do |raw_duration|
+ Gitlab::TimeTrackingFormatter.parse(raw_duration)
+ end
+ command :estimate do |time_estimate|
+ if time_estimate
+ @updates[:time_estimate] = time_estimate
+ end
+ end
+
+ desc 'Add or subtract spent time'
+ explanation do |time_spent, time_spent_date|
+ if time_spent
+ if time_spent > 0
+ verb = 'Adds'
+ value = time_spent
+ else
+ verb = 'Subtracts'
+ value = -time_spent
+ end
+
+ "#{verb} #{Gitlab::TimeTrackingFormatter.output(value)} spent time."
+ end
+ end
+ params '<time(1h30m | -1h30m)> <date(YYYY-MM-DD)>'
+ types Issue, MergeRequest
+ condition do
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ parse_params do |raw_time_date|
+ Gitlab::QuickActions::SpendTimeAndDateSeparator.new(raw_time_date).execute
+ end
+ command :spend do |time_spent, time_spent_date|
+ if time_spent
+ @updates[:spend_time] = {
+ duration: time_spent,
+ user_id: current_user.id,
+ spent_at: time_spent_date
+ }
+ end
+ end
+
+ desc 'Remove time estimate'
+ explanation 'Removes time estimate.'
+ types Issue, MergeRequest
+ condition do
+ quick_action_target.persisted? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ command :remove_estimate do
+ @updates[:time_estimate] = 0
+ end
+
+ desc 'Remove spent time'
+ explanation 'Removes spent time.'
+ condition do
+ quick_action_target.persisted? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
+ end
+ types Issue, MergeRequest
+ command :remove_time_spent do
+ @updates[:spend_time] = { duration: :reset, user_id: current_user.id }
+ end
+
+ desc "Lock the discussion"
+ explanation "Locks the discussion"
+ types Issue, MergeRequest
+ condition do
+ quick_action_target.persisted? &&
+ !quick_action_target.discussion_locked? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ command :lock do
+ @updates[:discussion_locked] = true
+ end
+
+ desc "Unlock the discussion"
+ explanation "Unlocks the discussion"
+ types Issue, MergeRequest
+ condition do
+ quick_action_target.persisted? &&
+ quick_action_target.discussion_locked? &&
+ current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
+ end
+ command :unlock do
+ @updates[:discussion_locked] = false
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/quick_actions/merge_request_actions.rb b/lib/gitlab/quick_actions/merge_request_actions.rb
new file mode 100644
index 00000000000..bade59182a1
--- /dev/null
+++ b/lib/gitlab/quick_actions/merge_request_actions.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module QuickActions
+ module MergeRequestActions
+ extend ActiveSupport::Concern
+ include Gitlab::QuickActions::Dsl
+
+ included do
+ # MergeRequest only quick actions definitions
+ desc 'Merge (when the pipeline succeeds)'
+ explanation 'Merges this merge request when the pipeline succeeds.'
+ types MergeRequest
+ condition do
+ last_diff_sha = params && params[:merge_request_diff_head_sha]
+ quick_action_target.persisted? &&
+ quick_action_target.mergeable_with_quick_action?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha)
+ end
+ command :merge do
+ @updates[:merge] = params[:merge_request_diff_head_sha]
+ end
+
+ desc 'Toggle the Work In Progress status'
+ explanation do
+ verb = quick_action_target.work_in_progress? ? 'Unmarks' : 'Marks'
+ noun = quick_action_target.to_ability_name.humanize(capitalize: false)
+ "#{verb} this #{noun} as Work In Progress."
+ end
+ types MergeRequest
+ condition do
+ quick_action_target.respond_to?(:work_in_progress?) &&
+ # Allow it to mark as WIP on MR creation page _or_ through MR notes.
+ (quick_action_target.new_record? || current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target))
+ end
+ command :wip do
+ @updates[:wip_event] = quick_action_target.work_in_progress? ? 'unwip' : 'wip'
+ end
+
+ desc 'Set target branch'
+ explanation do |branch_name|
+ "Sets target branch to #{branch_name}."
+ end
+ params '<Local branch name>'
+ types MergeRequest
+ condition do
+ quick_action_target.respond_to?(:target_branch) &&
+ (current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target) ||
+ quick_action_target.new_record?)
+ end
+ parse_params do |target_branch_param|
+ target_branch_param.strip
+ end
+ command :target_branch do |branch_name|
+ @updates[:target_branch] = branch_name if project.repository.branch_exists?(branch_name)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sentry/client.rb b/lib/sentry/client.rb
index 5e0c9101de5..bb1aa2a7a10 100644
--- a/lib/sentry/client.rb
+++ b/lib/sentry/client.rb
@@ -3,7 +3,7 @@
module Sentry
class Client
Error = Class.new(StandardError)
- SentryError = Class.new(StandardError)
+ MissingKeysError = Class.new(StandardError)
attr_accessor :url, :token
@@ -14,18 +14,29 @@ module Sentry
def list_issues(issue_status:, limit:)
issues = get_issues(issue_status: issue_status, limit: limit)
- map_to_errors(issues)
+
+ handle_mapping_exceptions do
+ map_to_errors(issues)
+ end
end
def list_projects
projects = get_projects
- map_to_projects(projects)
- rescue KeyError => e
- raise Client::SentryError, "Sentry API response is missing keys. #{e.message}"
+
+ handle_mapping_exceptions do
+ map_to_projects(projects)
+ end
end
private
+ def handle_mapping_exceptions(&block)
+ yield
+ rescue KeyError => e
+ Gitlab::Sentry.track_acceptable_exception(e)
+ raise Client::MissingKeysError, "Sentry API response is missing keys. #{e.message}"
+ end
+
def request_params
{
headers: {
@@ -94,7 +105,6 @@ module Sentry
def map_to_error(issue)
id = issue.fetch('id')
- project = issue.fetch('project')
count = issue.fetch('count', nil)
@@ -117,9 +127,9 @@ module Sentry
short_id: issue.fetch('shortId', nil),
status: issue.fetch('status', nil),
frequency: frequency,
- project_id: project.fetch('id'),
- project_name: project.fetch('name', nil),
- project_slug: project.fetch('slug', nil)
+ project_id: issue.dig('project', 'id'),
+ project_name: issue.dig('project', 'name'),
+ project_slug: issue.dig('project', 'slug')
)
end
@@ -127,12 +137,12 @@ module Sentry
organization = project.fetch('organization')
Gitlab::ErrorTracking::Project.new(
- id: project.fetch('id'),
+ id: project.fetch('id', nil),
name: project.fetch('name'),
slug: project.fetch('slug'),
status: project.dig('status'),
organization_name: organization.fetch('name'),
- organization_id: organization.fetch('id'),
+ organization_id: organization.fetch('id', nil),
organization_slug: organization.fetch('slug')
)
end
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index b94b21775ee..4e7a8adbef6 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -29,7 +29,10 @@ namespace :gitlab do
# If MySQL, turn off foreign key checks
connection.execute('SET FOREIGN_KEY_CHECKS=0') if Gitlab::Database.mysql?
- tables = connection.data_sources
+ # connection.tables is deprecated in MySQLAdapter, but in PostgreSQLAdapter
+ # data_sources returns both views and tables, so use #tables instead
+ tables = Gitlab::Database.mysql? ? connection.data_sources : connection.tables
+
# Removes the entry from the array
tables.delete 'schema_migrations'
# Truncate schema_migrations to ensure migrations re-run
diff --git a/lib/tasks/tokens.rake b/lib/tasks/tokens.rake
index eec024f9bbb..46635cd7c8f 100644
--- a/lib/tasks/tokens.rake
+++ b/lib/tasks/tokens.rake
@@ -24,7 +24,7 @@ namespace :tokens do
end
end
-class TmpUser < ActiveRecord::Base
+class TmpUser < ActiveRecord::Base # rubocop:disable Rails/ApplicationRecord
include TokenAuthenticatable
self.table_name = 'users'
diff --git a/package.json b/package.json
index cb063c9782c..f80f9b3690b 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.3.1",
"@gitlab/csslab": "^1.9.0",
- "@gitlab/svgs": "^1.54.0",
+ "@gitlab/svgs": "^1.57.0",
"@gitlab/ui": "^3.0.0",
"apollo-boost": "^0.3.1",
"apollo-client": "^2.5.1",
@@ -144,6 +144,7 @@
"babel-plugin-rewire": "^1.2.0",
"chalk": "^2.4.1",
"commander": "^2.18.0",
+ "custom-jquery-matchers": "^2.1.0",
"docdash": "^1.0.2",
"eslint": "~5.9.0",
"eslint-import-resolver-jest": "^2.1.1",
diff --git a/qa/qa/page/dashboard/groups.rb b/qa/qa/page/dashboard/groups.rb
index 7a07515de62..52853376f17 100644
--- a/qa/qa/page/dashboard/groups.rb
+++ b/qa/qa/page/dashboard/groups.rb
@@ -19,11 +19,13 @@ module QA
has_filtered_group?(name)
end
- def go_to_group(name)
+ def click_group(name)
+ raise "Group with name #{name} not found!" unless has_group?(name)
+
click_link name
end
- def go_to_new_group
+ def click_new_group
click_on 'New group'
end
end
diff --git a/qa/qa/page/dashboard/snippet/new.rb b/qa/qa/page/dashboard/snippet/new.rb
index a637b869d2f..4a8e65e20af 100644
--- a/qa/qa/page/dashboard/snippet/new.rb
+++ b/qa/qa/page/dashboard/snippet/new.rb
@@ -37,7 +37,7 @@ module QA
text_area.set content
end
- def create_snippet
+ def click_create_snippet_button
click_element :create_snippet_button
end
diff --git a/qa/qa/page/group/show.rb b/qa/qa/page/group/show.rb
index 41716326685..d4c4be0d6ca 100644
--- a/qa/qa/page/group/show.rb
+++ b/qa/qa/page/group/show.rb
@@ -18,7 +18,7 @@ module QA
element :no_result_text, 'No groups or projects matched your search' # rubocop:disable QA/ElementWithPattern
end
- def go_to_subgroup(name)
+ def click_subgroup(name)
click_link name
end
diff --git a/qa/qa/page/label/index.rb b/qa/qa/page/label/index.rb
index de0cfa9f293..e73d40b37ac 100644
--- a/qa/qa/page/label/index.rb
+++ b/qa/qa/page/label/index.rb
@@ -18,7 +18,7 @@ module QA
element :label_svg
end
- def go_to_new_label
+ def click_new_label_button
# The 'labels.svg' takes a fraction of a second to load after which the "New label" button shifts up a bit
# This can cause webdriver to miss the hit so we wait for the svg to load (implicitly with has_element?)
# before clicking the button.
diff --git a/qa/qa/page/label/new.rb b/qa/qa/page/label/new.rb
index b5422dc9400..9c8cf5f07e6 100644
--- a/qa/qa/page/label/new.rb
+++ b/qa/qa/page/label/new.rb
@@ -9,7 +9,7 @@ module QA
element :label_create_button
end
- def create_label
+ def click_label_create_button
click_element :label_create_button
end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 1b3445b0064..e98d531c86e 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -47,7 +47,7 @@ module QA
end
end
- def go_to_admin_area
+ def click_admin_area
within_top_menu { click_element :admin_area_link }
end
@@ -57,7 +57,7 @@ module QA
end
end
- def go_to_profile_settings
+ def click_settings_link
retry_until(reload: false) do
within_user_menu do
click_link 'Settings'
@@ -67,7 +67,7 @@ module QA
end
end
- def go_to_snippets
+ def click_snippets_link
click_element :snippets_link
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index c0411db6505..5aef868a805 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -145,11 +145,11 @@ module QA
click_element :squash_checkbox
end
- def go_to_discussions_tab
+ def click_discussions_tab
click_element :notes_tab
end
- def go_to_diffs_tab
+ def click_diffs_tab
click_element :diffs_tab
end
diff --git a/qa/qa/page/profile/personal_access_tokens.rb b/qa/qa/page/profile/personal_access_tokens.rb
index 8c12eff5cf1..c9a5a1b3ca0 100644
--- a/qa/qa/page/profile/personal_access_tokens.rb
+++ b/qa/qa/page/profile/personal_access_tokens.rb
@@ -26,7 +26,7 @@ module QA
check_element(:api_radio)
end
- def create_token
+ def click_create_token_button
click_element(:create_token_button)
end
diff --git a/qa/qa/page/project/issue/index.rb b/qa/qa/page/project/issue/index.rb
index 1035bf74a43..e987d279e21 100644
--- a/qa/qa/page/project/issue/index.rb
+++ b/qa/qa/page/project/issue/index.rb
@@ -7,7 +7,7 @@ module QA
element :issue_link, 'link_to issue.title' # rubocop:disable QA/ElementWithPattern
end
- def go_to_issue(title)
+ def click_issue_link(title)
click_link(title)
end
end
diff --git a/qa/qa/page/project/milestone/new.rb b/qa/qa/page/project/milestone/new.rb
index 992ef89004b..0db8d2cf766 100644
--- a/qa/qa/page/project/milestone/new.rb
+++ b/qa/qa/page/project/milestone/new.rb
@@ -17,7 +17,7 @@ module QA
fill_element :milestone_description, description
end
- def create_new_milestone
+ def click_milestone_create_button
click_element :milestone_create_button
end
end
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index 552b2293115..f841afbbffd 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -35,7 +35,7 @@ module QA
end
end
- def go_to_import_project
+ def click_import_project
click_on 'Import project'
end
@@ -51,7 +51,7 @@ module QA
click_on 'Create project'
end
- def go_to_create_from_template
+ def click_create_from_template_tab
click_element(:project_create_from_template_tab)
end
@@ -59,7 +59,7 @@ module QA
choose visibility
end
- def go_to_github_import
+ def click_github_link
click_link 'GitHub'
end
end
diff --git a/qa/qa/page/project/operations/environments/index.rb b/qa/qa/page/project/operations/environments/index.rb
index 63965a57edd..610a34385b1 100644
--- a/qa/qa/page/project/operations/environments/index.rb
+++ b/qa/qa/page/project/operations/environments/index.rb
@@ -10,7 +10,7 @@ module QA
element :environment_link
end
- def go_to_environment(environment_name)
+ def click_environment_link(environment_name)
wait(reload: false) do
find(element_selector_css(:environment_link), text: environment_name).click
end
diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb
index 19d83ecc4f4..0373a12f597 100644
--- a/qa/qa/page/project/pipeline/index.rb
+++ b/qa/qa/page/project/pipeline/index.rb
@@ -5,7 +5,7 @@ module QA::Page
element :pipeline_link, 'class="js-pipeline-url-link"' # rubocop:disable QA/ElementWithPattern
end
- def go_to_latest_pipeline
+ def click_on_latest_pipeline
css = '.js-pipeline-url-link'
link = wait(reload: false) do
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index 6f8a66bf527..9c0b55b1c4c 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -42,11 +42,11 @@ module QA::Page
end
end
- def go_to_job(job_name)
+ def click_job(job_name)
find_element(:job_link, text: job_name).click
end
- def go_to_first_job
+ def click_on_first_job
css = '.js-pipeline-graph-job-link'
wait(reload: false) do
diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb
index 76591a4e3fe..399a49d2420 100644
--- a/qa/qa/page/project/settings/protected_branches.rb
+++ b/qa/qa/page/project/settings/protected_branches.rb
@@ -32,22 +32,22 @@ module QA
end
def allow_no_one_to_push
- click_allow(:push, 'No one')
+ go_to_allow(:push, 'No one')
end
def allow_devs_and_maintainers_to_push
- click_allow(:push, 'Developers + Maintainers')
+ go_to_allow(:push, 'Developers + Maintainers')
end
# @deprecated
alias_method :allow_devs_and_masters_to_push, :allow_devs_and_maintainers_to_push
def allow_no_one_to_merge
- click_allow(:merge, 'No one')
+ go_to_allow(:merge, 'No one')
end
def allow_devs_and_maintainers_to_merge
- click_allow(:merge, 'Developers + Maintainers')
+ go_to_allow(:merge, 'Developers + Maintainers')
end
# @deprecated
@@ -59,7 +59,7 @@ module QA
private
- def click_allow(action, text)
+ def go_to_allow(action, text)
click_element :"allowed_to_#{action}_select"
within_element(:"allowed_to_#{action}_dropdown") do
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 9c21d9ddbfa..1a9a2fd413f 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -76,13 +76,13 @@ module QA
click_on 'Fork'
end
- def go_to_file(filename)
+ def click_file(filename)
within_element(:file_tree) do
click_on filename
end
end
- def go_to_commit(commit_msg)
+ def click_commit(commit_msg)
within_element(:file_tree) do
click_on commit_msg
end
diff --git a/qa/qa/page/project/sub_menus/operations.rb b/qa/qa/page/project/sub_menus/operations.rb
index cf9fc453565..24a99a9464c 100644
--- a/qa/qa/page/project/sub_menus/operations.rb
+++ b/qa/qa/page/project/sub_menus/operations.rb
@@ -14,7 +14,7 @@ module QA
end
end
- def click_operations_environments
+ def go_to_operations_environments
hover_operations do
within_submenu do
click_element(:operations_environments_link)
@@ -22,7 +22,7 @@ module QA
end
end
- def click_operations_kubernetes
+ def go_to_operations_kubernetes
hover_operations do
within_submenu do
click_link('Kubernetes')
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index 29eaa9a74de..4cc73a6b25a 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -20,7 +20,7 @@ module QA
end
end
- def click_repository_branches
+ def go_to_repository_branches
hover_repository do
within_submenu do
click_element(:branches_link)
diff --git a/qa/qa/page/project/sub_menus/settings.rb b/qa/qa/page/project/sub_menus/settings.rb
index 62c594c0210..22743ebd0a1 100644
--- a/qa/qa/page/project/sub_menus/settings.rb
+++ b/qa/qa/page/project/sub_menus/settings.rb
@@ -14,7 +14,7 @@ module QA
end
end
- def click_ci_cd_settings
+ def go_to_ci_cd_settings
hover_settings do
within_submenu do
click_link('CI / CD')
@@ -22,7 +22,7 @@ module QA
end
end
- def click_members_settings
+ def go_to_members_settings
hover_settings do
within_submenu do
click_element :link_members_settings
@@ -30,7 +30,7 @@ module QA
end
end
- def click_repository_settings
+ def go_to_repository_settings
hover_settings do
within_submenu do
click_link('Repository')
@@ -38,7 +38,7 @@ module QA
end
end
- def go_to_settings
+ def click_settings
within_sidebar do
click_on 'Settings'
end
diff --git a/qa/qa/page/project/wiki/edit.rb b/qa/qa/page/project/wiki/edit.rb
index 8d0eafa1818..1ccd67349c3 100644
--- a/qa/qa/page/project/wiki/edit.rb
+++ b/qa/qa/page/project/wiki/edit.rb
@@ -9,15 +9,7 @@ module QA
element :edit_page_link, 'Edit' # rubocop:disable QA/ElementWithPattern
end
- def go_to_new_page
- click_on 'New page'
- end
-
- def got_to_view_history_page
- click_on 'Page history'
- end
-
- def go_to_edit_page
+ def click_edit
click_on 'Edit'
end
end
diff --git a/qa/qa/page/project/wiki/new.rb b/qa/qa/page/project/wiki/new.rb
index b90e03be36a..792eba4bab7 100644
--- a/qa/qa/page/project/wiki/new.rb
+++ b/qa/qa/page/project/wiki/new.rb
@@ -23,7 +23,7 @@ module QA
element :svg_content
end
- def go_to_create_first_page
+ def click_create_your_first_page_button
# The svg takes a fraction of a second to load after which the
# "Create your first page" button shifts up a bit. This can cause
# webdriver to miss the hit so we wait for the svg to load before
diff --git a/qa/qa/page/project/wiki/show.rb b/qa/qa/page/project/wiki/show.rb
index dffbc5d60a2..f79ad510084 100644
--- a/qa/qa/page/project/wiki/show.rb
+++ b/qa/qa/page/project/wiki/show.rb
@@ -11,7 +11,7 @@ module QA
element :clone_repository_link, 'Clone repository' # rubocop:disable QA/ElementWithPattern
end
- def go_to_clone_repository
+ def click_clone_repository
click_on 'Clone repository'
end
end
diff --git a/qa/qa/resource/branch.rb b/qa/qa/resource/branch.rb
index bd52c4abe02..a45dd030625 100644
--- a/qa/qa/resource/branch.rb
+++ b/qa/qa/resource/branch.rb
@@ -46,7 +46,7 @@ module QA
# to `allow_to_push` variable.
return branch unless @protected
- Page::Project::Menu.perform(&:click_repository_settings)
+ Page::Project::Menu.perform(&:go_to_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_protected_branches do |page|
diff --git a/qa/qa/resource/ci_variable.rb b/qa/qa/resource/ci_variable.rb
index 0570c47d41c..d82de4cb816 100644
--- a/qa/qa/resource/ci_variable.rb
+++ b/qa/qa/resource/ci_variable.rb
@@ -15,7 +15,7 @@ module QA
def fabricate!
project.visit!
- Page::Project::Menu.perform(&:click_ci_cd_settings)
+ Page::Project::Menu.perform(&:go_to_ci_cd_settings)
Page::Project::Settings::CICD.perform do |setting|
setting.expand_ci_variables do |page|
diff --git a/qa/qa/resource/deploy_key.rb b/qa/qa/resource/deploy_key.rb
index 9565598efb0..869e2a71e47 100644
--- a/qa/qa/resource/deploy_key.rb
+++ b/qa/qa/resource/deploy_key.rb
@@ -23,7 +23,7 @@ module QA
def fabricate!
project.visit!
- Page::Project::Menu.perform(&:click_repository_settings)
+ Page::Project::Menu.perform(&:go_to_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_deploy_keys do |page|
diff --git a/qa/qa/resource/deploy_token.rb b/qa/qa/resource/deploy_token.rb
index cee4422f6b4..fca5ed83c87 100644
--- a/qa/qa/resource/deploy_token.rb
+++ b/qa/qa/resource/deploy_token.rb
@@ -32,7 +32,7 @@ module QA
project.visit!
Page::Project::Menu.act do
- click_repository_settings
+ go_to_repository_settings
end
Page::Project::Settings::Repository.perform do |setting|
diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb
index d7f9ec6a836..0b567a474c8 100644
--- a/qa/qa/resource/group.rb
+++ b/qa/qa/resource/group.rb
@@ -21,7 +21,7 @@ module QA
Page::Group::Show.perform do |group_show|
if group_show.has_subgroup?(path)
- group_show.go_to_subgroup(path)
+ group_show.click_subgroup(path)
else
group_show.go_to_new_subgroup
diff --git a/qa/qa/resource/kubernetes_cluster.rb b/qa/qa/resource/kubernetes_cluster.rb
index 93a06be6818..27ab7b60211 100644
--- a/qa/qa/resource/kubernetes_cluster.rb
+++ b/qa/qa/resource/kubernetes_cluster.rb
@@ -16,7 +16,7 @@ module QA
@project.visit!
Page::Project::Menu.perform(
- &:click_operations_kubernetes)
+ &:go_to_operations_kubernetes)
Page::Project::Operations::Kubernetes::Index.perform(
&:add_kubernetes_cluster)
diff --git a/qa/qa/resource/label.rb b/qa/qa/resource/label.rb
index c0869cb1f2a..7c899db31f3 100644
--- a/qa/qa/resource/label.rb
+++ b/qa/qa/resource/label.rb
@@ -25,13 +25,13 @@ module QA
project.visit!
Page::Project::Menu.perform(&:go_to_labels)
- Page::Label::Index.perform(&:go_to_new_label)
+ Page::Label::Index.perform(&:click_new_label_button)
Page::Label::New.perform do |page|
page.fill_title(@title)
page.fill_description(@description)
page.fill_color(@color)
- page.create_label
+ page.click_label_create_button
end
end
end
diff --git a/qa/qa/resource/personal_access_token.rb b/qa/qa/resource/personal_access_token.rb
index b8dd0a3562f..f5c632cd8d2 100644
--- a/qa/qa/resource/personal_access_token.rb
+++ b/qa/qa/resource/personal_access_token.rb
@@ -13,13 +13,13 @@ module QA
end
def fabricate!
- Page::Main::Menu.perform(&:go_to_profile_settings)
+ Page::Main::Menu.perform(&:click_settings_link)
Page::Profile::Menu.perform(&:click_access_tokens)
Page::Profile::PersonalAccessTokens.perform do |page|
page.fill_token_name(name || 'api-test-token')
page.check_api
- page.create_token
+ page.click_create_token_button
end
end
end
diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb
index 0d25e7dd842..a160cdb3273 100644
--- a/qa/qa/resource/project_imported_from_github.rb
+++ b/qa/qa/resource/project_imported_from_github.rb
@@ -18,11 +18,11 @@ module QA
Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |page|
- page.go_to_import_project
+ page.click_import_project
end
Page::Project::New.perform do |page|
- page.go_to_github_import
+ page.click_github_link
end
Page::Project::Import::Github.perform do |page|
diff --git a/qa/qa/resource/project_milestone.rb b/qa/qa/resource/project_milestone.rb
index a4d6657caff..8ace75f695a 100644
--- a/qa/qa/resource/project_milestone.rb
+++ b/qa/qa/resource/project_milestone.rb
@@ -28,7 +28,7 @@ module QA
Page::Project::Milestone::New.perform do |milestone_new|
milestone_new.set_title(@title)
milestone_new.set_description(@description)
- milestone_new.create_new_milestone
+ milestone_new.click_milestone_create_button
end
end
end
diff --git a/qa/qa/resource/repository/wiki_push.rb b/qa/qa/resource/repository/wiki_push.rb
index 77c4c8a514d..95712300854 100644
--- a/qa/qa/resource/repository/wiki_push.rb
+++ b/qa/qa/resource/repository/wiki_push.rb
@@ -24,7 +24,7 @@ module QA
@repository_http_uri ||= begin
wiki.visit!
Page::Project::Wiki::Show.act do
- go_to_clone_repository
+ click_clone_repository
choose_repository_clone_http
repository_location.uri
end
diff --git a/qa/qa/resource/runner.rb b/qa/qa/resource/runner.rb
index 08ae3f22117..3344ad3360a 100644
--- a/qa/qa/resource/runner.rb
+++ b/qa/qa/resource/runner.rb
@@ -29,7 +29,7 @@ module QA
def fabricate!
project.visit!
- Page::Project::Menu.perform(&:click_ci_cd_settings)
+ Page::Project::Menu.perform(&:go_to_ci_cd_settings)
Service::Runner.new(name).tap do |runner|
Page::Project::Settings::CICD.perform do |settings|
diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb
index 41ce857a8b8..942eea5cc40 100644
--- a/qa/qa/resource/sandbox.rb
+++ b/qa/qa/resource/sandbox.rb
@@ -20,9 +20,9 @@ module QA
Page::Dashboard::Groups.perform do |page|
if page.has_group?(path)
- page.go_to_group(path)
+ page.click_group(path)
else
- page.go_to_new_group
+ page.click_new_group
Page::Group::New.perform do |group|
group.set_path(path)
diff --git a/qa/qa/resource/settings/hashed_storage.rb b/qa/qa/resource/settings/hashed_storage.rb
index 40c06768ffe..08bb95cfd4b 100644
--- a/qa/qa/resource/settings/hashed_storage.rb
+++ b/qa/qa/resource/settings/hashed_storage.rb
@@ -8,7 +8,7 @@ module QA
raise ArgumentError unless traits.include?(:enabled)
Page::Main::Login.perform(&:sign_in_using_credentials)
- Page::Main::Menu.perform(&:go_to_admin_area)
+ Page::Main::Menu.perform(&:click_admin_area)
Page::Admin::Menu.perform(&:go_to_repository_settings)
Page::Admin::Settings::Repository.perform do |setting|
diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb
index 1478f197570..f58d7b5113f 100644
--- a/qa/qa/resource/snippet.rb
+++ b/qa/qa/resource/snippet.rb
@@ -22,7 +22,7 @@ module QA
page.set_visibility(@visibility)
page.fill_file_name(@file_name)
page.fill_file_content(@file_content)
- page.create_snippet
+ page.click_create_snippet_button
end
end
end
diff --git a/qa/qa/resource/ssh_key.rb b/qa/qa/resource/ssh_key.rb
index c6c97c8532f..4e399ae730e 100644
--- a/qa/qa/resource/ssh_key.rb
+++ b/qa/qa/resource/ssh_key.rb
@@ -14,7 +14,7 @@ module QA
end
def fabricate!
- Page::Main::Menu.perform(&:go_to_profile_settings)
+ Page::Main::Menu.perform(&:click_settings_link)
Page::Profile::Menu.perform(&:click_ssh_keys)
Page::Profile::SSHKeys.perform do |page|
diff --git a/qa/qa/resource/wiki.rb b/qa/qa/resource/wiki.rb
index e942e9718a0..0a776f22e25 100644
--- a/qa/qa/resource/wiki.rb
+++ b/qa/qa/resource/wiki.rb
@@ -18,7 +18,7 @@ module QA
Page::Project::Menu.perform { |menu_side| menu_side.click_wiki }
Page::Project::Wiki::New.perform do |wiki_new|
- wiki_new.go_to_create_first_page
+ wiki_new.click_create_your_first_page_button
wiki_new.set_title(@title)
wiki_new.set_content(@content)
wiki_new.set_message(@message)
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
index d8609aa037a..d1747280227 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
@@ -14,7 +14,7 @@ module QA
end
project.visit!
- Page::Project::Menu.perform(&:click_members_settings)
+ Page::Project::Menu.perform(&:go_to_members_settings)
Page::Project::Settings::Members.perform do |page|
page.add_member(user.username)
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
index 3fbcd77dac6..7a36f9ea420 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
@@ -12,7 +12,7 @@ module QA
end
project.visit!
- Page::Project::Menu.perform(&:go_to_settings)
+ Page::Project::Menu.perform(&:click_settings)
Page::Project::Settings::MergeRequest.perform(&:enable_ff_only)
merge_request = Resource::MergeRequest.fabricate! do |merge_request|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
index 8e181eb28c6..daeee665c93 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
@@ -57,7 +57,7 @@ module QA
end
it 'branches are correctly listed after CRUD operations' do
- Page::Project::Menu.perform(&:click_repository_branches)
+ Page::Project::Menu.perform(&:go_to_repository_branches)
expect(page).to have_content(master_branch)
expect(page).to have_content(second_branch)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
index ff879fdeb16..f41240b7605 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
@@ -16,7 +16,7 @@ module QA
expect(page).to have_content("Title: #{key_title}")
expect(page).to have_content(key.fingerprint)
- Page::Main::Menu.act { go_to_profile_settings }
+ Page::Main::Menu.act { click_settings_link }
Page::Profile::Menu.act { click_ssh_keys }
Page::Profile::SSHKeys.perform do |ssh_keys|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb
index eb59b54e9ab..dc42191b448 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb
@@ -31,7 +31,7 @@ module QA
# Remove the SSH key
login
- Page::Main::Menu.perform(&:go_to_profile_settings)
+ Page::Main::Menu.perform(&:click_settings_link)
Page::Profile::Menu.perform(&:click_ssh_keys)
Page::Profile::SSHKeys.perform do |ssh_keys|
ssh_keys.remove_key(key_title)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
index 99601e3d230..23008a58af8 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
@@ -21,7 +21,7 @@ module QA
end
source_project_push.project.visit!
- Page::Project::Menu.perform(&:click_repository_settings)
+ Page::Project::Menu.perform(&:go_to_repository_settings)
Page::Project::Settings::Repository.perform do |settings|
settings.expand_mirroring_repositories do |mirror_settings|
# Configure the source project to push to the target project
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
index 243f0b83b77..a544efb35ee 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
@@ -40,12 +40,12 @@ module QA
set_file_size_limit(1)
expect(page).to have_content("Application settings saved successfully")
- push = push_new_file('oversize_file_2.bin', wait_for_push: false)
- expect(push.output).to have_content 'remote: fatal: pack exceeds maximum allowed size'
+ expect { push_new_file('oversize_file_2.bin', wait_for_push: false) }
+ .to raise_error(QA::Git::Repository::RepositoryCommandError, /remote: fatal: pack exceeds maximum allowed size/)
end
def set_file_size_limit(limit)
- Page::Main::Menu.perform(&:go_to_admin_area)
+ Page::Main::Menu.perform(&:click_admin_area)
Page::Admin::Menu.perform(&:go_to_general_settings)
Page::Admin::Settings::General.perform do |setting|
@@ -65,6 +65,7 @@ module QA
p.file_content = SecureRandom.random_bytes(2000000)
p.commit_message = 'Adding a new file'
p.wait_for_push = wait_for_push
+ p.new_branch = false
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
index 7223831d96f..a0251e1c385 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
@@ -28,7 +28,7 @@ module QA
expect(page).to have_content('README.md')
expect(page).to have_content('Test Use SSH Key')
- Page::Main::Menu.perform(&:go_to_profile_settings)
+ Page::Main::Menu.perform(&:click_settings_link)
Page::Profile::Menu.perform(&:click_ssh_keys)
Page::Profile::SSHKeys.perform do |ssh_keys|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
index b862a7bd1ed..b7400cdca97 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
@@ -33,7 +33,7 @@ module QA
def view_commit
@project.visit!
Page::Project::Show.perform do |page|
- page.go_to_commit(@commit_message)
+ page.click_commit(@commit_message)
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb
index ab53dff464e..b643468a664 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb
@@ -7,7 +7,7 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- Page::Main::Menu.perform(&:go_to_snippets)
+ Page::Main::Menu.perform(&:click_snippets_link)
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
snippet.title = 'Snippet title'
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
index 29589ec870a..309ae6cd986 100644
--- a/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
@@ -20,7 +20,7 @@ module QA
validate_content('My First Wiki Content')
- Page::Project::Wiki::Edit.perform(&:go_to_edit_page)
+ Page::Project::Wiki::Edit.perform(&:click_edit)
Page::Project::Wiki::New.perform do |page|
page.set_content("My Second Wiki Content")
page.save_changes
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
index 2238d6c382e..7c1d4489c47 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
@@ -70,7 +70,7 @@ module QA
puts 'Waiting for the runner to process the pipeline'
sleep 15 # Runner should process all jobs within 15 seconds.
- Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
+ Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
expect(pipeline).to be_running
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
index 3f65eabc756..609155da855 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
@@ -91,8 +91,8 @@ module QA
sha1sum = Digest::SHA1.hexdigest(gitlab_ci)
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
- Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
- Page::Project::Pipeline::Show.perform(&:go_to_first_job)
+ Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
+ Page::Project::Pipeline::Show.perform(&:click_on_first_job)
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index ceb888bb4ef..bb1f775da75 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -63,10 +63,10 @@ module QA
end
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
- Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
+ Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.go_to_job('build')
+ pipeline.click_job('build')
end
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 600)
@@ -75,7 +75,7 @@ module QA
end
Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.go_to_job('test')
+ pipeline.click_job('test')
end
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 600)
@@ -84,7 +84,7 @@ module QA
end
Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.go_to_job('production')
+ pipeline.click_job('production')
end
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 1200)
@@ -92,9 +92,9 @@ module QA
job.click_element(:pipeline_path)
end
- Page::Project::Menu.perform(&:click_operations_environments)
+ Page::Project::Menu.perform(&:go_to_operations_environments)
Page::Project::Operations::Environments::Index.perform do |index|
- index.go_to_environment('production')
+ index.click_environment_link('production')
end
Page::Project::Operations::Environments::Show.perform do |show|
show.view_deployment do
@@ -125,7 +125,7 @@ module QA
end
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
- Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
+ Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
expect(pipeline).to have_tag('Auto DevOps')
diff --git a/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb
index 7096864e011..8383dcdb983 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb
@@ -9,7 +9,7 @@ module QA
Page::Main::Menu.act { go_to_groups }
Page::Dashboard::Groups.perform do |page|
- page.go_to_new_group
+ page.click_new_group
expect(page).to have_content(
/Create a Mattermost team for this group/
diff --git a/qa/qa/tools/revoke_all_personal_access_tokens.rb b/qa/qa/tools/revoke_all_personal_access_tokens.rb
index 7484b633bf6..8a74f52324d 100644
--- a/qa/qa/tools/revoke_all_personal_access_tokens.rb
+++ b/qa/qa/tools/revoke_all_personal_access_tokens.rb
@@ -27,7 +27,7 @@ module QA
Runtime::Browser.visit(ENV['GITLAB_ADDRESS'], Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- Page::Main::Menu.perform(&:go_to_profile_settings)
+ Page::Main::Menu.perform(&:click_settings_link)
Page::Profile::Menu.perform(&:click_access_tokens)
token_name = 'api-test-token'
diff --git a/scripts/insert-rspec-profiling-data b/scripts/insert-rspec-profiling-data
index 10e337b9972..b34379764e0 100755
--- a/scripts/insert-rspec-profiling-data
+++ b/scripts/insert-rspec-profiling-data
@@ -22,7 +22,7 @@ module RspecProfiling
ENV['RSPEC_PROFILING_POSTGRES_URL']
end
- class Result < ActiveRecord::Base
+ class Result < ActiveRecord::Base # rubocop:disable Rails/ApplicationRecord
acts_as_copy_target
end
end
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 32fce946c17..e324f972640 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -1,12 +1,115 @@
[[ "$TRACE" ]] && set -x
export TILLER_NAMESPACE="$KUBE_NAMESPACE"
-function echoerr() { printf "\033[0;31m%s\n\033[0m" "$*" >&2; }
-function echoinfo() { printf "\033[0;33m%s\n\033[0m" "$*" >&2; }
+function echoerr() {
+ local header="${2}"
+
+ if [ -n "${header}" ]; then
+ printf "\n\033[0;31m** %s **\n\033[0m" "${1}" >&2;
+ else
+ printf "\033[0;31m%s\n\033[0m" "${1}" >&2;
+ fi
+}
+
+function echoinfo() {
+ local header="${2}"
+
+ if [ -n "${header}" ]; then
+ printf "\n\033[0;33m** %s **\n\033[0m" "${1}" >&2;
+ else
+ printf "\033[0;33m%s\n\033[0m" "${1}" >&2;
+ fi
+}
+
+function deployExists() {
+ local namespace="${1}"
+ local deploy="${2}"
+ echoinfo "Checking if ${deploy} exists in the ${namespace} namespace..." true
+
+ helm status --tiller-namespace "${namespace}" "${deploy}" >/dev/null 2>&1
+ local deploy_exists=$?
+
+ echoinfo "Deployment status for ${deploy} is ${deploy_exists}"
+ return $deploy_exists
+}
+
+function previousDeployFailed() {
+ set +e
+ local deploy="${1}"
+ echoinfo "Checking for previous deployment of ${deploy}" true
+
+ helm status ${deploy} >/dev/null 2>&1
+ local status=$?
+
+ # if `status` is `0`, deployment exists, has a status
+ if [ $status -eq 0 ]; then
+ echoinfo "Previous deployment found, checking status..."
+ deployment_status=$(helm status ${deploy} | grep ^STATUS | cut -d' ' -f2)
+ echoinfo "Previous deployment state: ${deployment_status}"
+ if [[ "$deployment_status" == "FAILED" || "$deployment_status" == "PENDING_UPGRADE" || "$deployment_status" == "PENDING_INSTALL" ]]; then
+ status=0;
+ else
+ status=1;
+ fi
+ else
+ echoerr "Previous deployment NOT found."
+ fi
+ set -e
+ return $status
+}
+
+function delete() {
+ if [ -z "$CI_ENVIRONMENT_SLUG" ]; then
+ echoerr "No release given, aborting the delete!"
+ return
+ fi
+
+ local track="${1-stable}"
+ local name="$CI_ENVIRONMENT_SLUG"
+
+ if [[ "$track" != "stable" ]]; then
+ name="$name-$track"
+ fi
+
+ echoinfo "Deleting release '$name'..." true
+
+ helm delete --purge "$name" || true
+}
+
+function cleanup() {
+ if [ -z "$CI_ENVIRONMENT_SLUG" ]; then
+ echoerr "No release given, aborting the delete!"
+ return
+ fi
+
+ echoinfo "Cleaning up '$CI_ENVIRONMENT_SLUG'..." true
+
+ kubectl -n "$KUBE_NAMESPACE" delete \
+ ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa \
+ -l release="$CI_ENVIRONMENT_SLUG" \
+ || true
+}
+
+function get_pod() {
+ local app_name="${1}"
+ local status="${2-Running}"
+ get_pod_cmd="kubectl get pods -n ${KUBE_NAMESPACE} --field-selector=status.phase=${status} -lapp=${app_name},release=${CI_ENVIRONMENT_SLUG} --no-headers -o=custom-columns=NAME:.metadata.name"
+ echoinfo "Running '${get_pod_cmd}'" true
+
+ while true; do
+ local pod_name="$(eval $get_pod_cmd)"
+ [[ "${pod_name}" == "" ]] || break
+
+ echoinfo "Waiting till '${app_name}' pod is ready";
+ sleep 5;
+ done
+
+ echoinfo "The pod name is '${pod_name}'."
+ echo "${pod_name}"
+}
function perform_review_app_deployment() {
check_kube_domain
- download_gitlab_chart
ensure_namespace
install_tiller
install_external_dns
@@ -15,6 +118,8 @@ function perform_review_app_deployment() {
}
function check_kube_domain() {
+ echoinfo "Checking that Kube domain exists..." true
+
if [ -z ${REVIEW_APPS_DOMAIN+x} ]; then
echo "In order to deploy or use Review Apps, REVIEW_APPS_DOMAIN variable must be set"
echo "You can do it in Auto DevOps project settings or defining a variable at group or project level"
@@ -25,36 +130,56 @@ function check_kube_domain() {
fi
}
-function download_gitlab_chart() {
- curl -o gitlab.tar.bz2 https://gitlab.com/charts/gitlab/-/archive/$GITLAB_HELM_CHART_REF/gitlab-$GITLAB_HELM_CHART_REF.tar.bz2
- tar -xjf gitlab.tar.bz2
- cd gitlab-$GITLAB_HELM_CHART_REF
-
- helm init --client-only
- helm repo add gitlab https://charts.gitlab.io
- helm dependency update
- helm dependency build
-}
-
function ensure_namespace() {
+ echoinfo "Ensuring the ${KUBE_NAMESPACE} namespace exists..." true
+
kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE"
}
function install_tiller() {
- echo "Checking Tiller..."
+ echoinfo "Checking deployment/tiller-deploy status in the ${TILLER_NAMESPACE} namespace..." true
+
+ echoinfo "Initiating the Helm client..."
+ helm init --client-only
+
helm init \
--upgrade \
--replicas 2
+
kubectl rollout status -n "$TILLER_NAMESPACE" -w "deployment/tiller-deploy"
+
if ! helm version --debug; then
echo "Failed to init Tiller."
return 1
fi
- echo ""
+}
+
+function install_external_dns() {
+ local release_name="dns-gitlab-review-app"
+ local domain=$(echo "${REVIEW_APPS_DOMAIN}" | awk -F. '{printf "%s.%s", $(NF-1), $NF}')
+ echoinfo "Installing external DNS for domain ${domain}..." true
+
+ if ! deployExists "${KUBE_NAMESPACE}" "${release_name}" || previousDeployFailed "${release_name}" ; then
+ echoinfo "Installing external-dns Helm chart"
+ helm repo update
+ helm install stable/external-dns \
+ -n "${release_name}" \
+ --namespace "${KUBE_NAMESPACE}" \
+ --set provider="aws" \
+ --set aws.secretKey="${REVIEW_APPS_AWS_SECRET_KEY}" \
+ --set aws.accessKey="${REVIEW_APPS_AWS_ACCESS_KEY}" \
+ --set aws.zoneType="public" \
+ --set domainFilters[0]="${domain}" \
+ --set txtOwnerId="${KUBE_NAMESPACE}" \
+ --set rbac.create="true" \
+ --set policy="sync"
+ else
+ echoinfo "The external-dns Helm chart is already successfully deployed."
+ fi
}
function create_secret() {
- echo "Create secret..."
+ echoinfo "Creating the ${CI_ENVIRONMENT_SLUG}-gitlab-initial-root-password secret in the ${KUBE_NAMESPACE} namespace..." true
kubectl create secret generic -n "$KUBE_NAMESPACE" \
$CI_ENVIRONMENT_SLUG-gitlab-initial-root-password \
@@ -62,43 +187,28 @@ function create_secret() {
--dry-run -o json | kubectl apply -f -
}
-function deployExists() {
- local namespace="${1}"
- local deploy="${2}"
- helm status --tiller-namespace "${namespace}" "${deploy}" >/dev/null 2>&1
- return $?
-}
+function download_gitlab_chart() {
+ echoinfo "Downloading the GitLab chart..." true
-function previousDeployFailed() {
- set +e
- deploy="${1}"
- echo "Checking for previous deployment of ${deploy}"
- deployment_status=$(helm status ${deploy} >/dev/null 2>&1)
- status=$?
- # if `status` is `0`, deployment exists, has a status
- if [ $status -eq 0 ]; then
- echo "Previous deployment found, checking status"
- deployment_status=$(helm status ${deploy} | grep ^STATUS | cut -d' ' -f2)
- echo "Previous deployment state: $deployment_status"
- if [[ "$deployment_status" == "FAILED" || "$deployment_status" == "PENDING_UPGRADE" || "$deployment_status" == "PENDING_INSTALL" ]]; then
- status=0;
- else
- status=1;
- fi
- else
- echo "Previous deployment NOT found."
- fi
- set -e
- return $status
+ curl -o gitlab.tar.bz2 https://gitlab.com/charts/gitlab/-/archive/$GITLAB_HELM_CHART_REF/gitlab-$GITLAB_HELM_CHART_REF.tar.bz2
+ tar -xjf gitlab.tar.bz2
+ cd gitlab-$GITLAB_HELM_CHART_REF
+
+ echoinfo "Adding the gitlab repo to Helm..."
+ helm repo add gitlab https://charts.gitlab.io
+
+ echoinfo "Building the gitlab chart's dependencies..."
+ helm dependency build .
}
function deploy() {
- track="${1-stable}"
- name="$CI_ENVIRONMENT_SLUG"
+ local track="${1-stable}"
+ local name="$CI_ENVIRONMENT_SLUG"
if [[ "$track" != "stable" ]]; then
name="$name-$track"
fi
+ echoinfo "Deploying ${name}..." true
replicas="1"
service_enabled="false"
@@ -140,9 +250,7 @@ function deploy() {
fi
create_secret
-
- helm repo add gitlab https://charts.gitlab.io/
- helm dep update .
+ download_gitlab_chart
HELM_CMD=$(cat << EOF
helm upgrade --install \
@@ -188,92 +296,20 @@ HELM_CMD=$(cat << EOF
EOF
)
- echo "Deploying with:"
- echo $HELM_CMD
+ echoinfo "Deploying with:"
+ echoinfo "${HELM_CMD}"
eval $HELM_CMD
}
-function delete() {
- track="${1-stable}"
- name="$CI_ENVIRONMENT_SLUG"
-
- if [ -z "$CI_ENVIRONMENT_SLUG" ]; then
- echo "No release given, aborting the delete!"
- return
- fi
-
- if [[ "$track" != "stable" ]]; then
- name="$name-$track"
- fi
-
- if ! deployExists "${KUBE_NAMESPACE}" "${name}"; then
- echo "The release $name doesn't exist, aborting the cleanup!"
- return
- fi
-
- echo "Deleting release '$name'..."
- helm delete --purge "$name" || true
-}
-
-function cleanup() {
- if [ -z "$CI_ENVIRONMENT_SLUG" ]; then
- echo "No release given, aborting the delete!"
- return
- fi
-
- echo "Cleaning up '$CI_ENVIRONMENT_SLUG'..."
- kubectl -n "$KUBE_NAMESPACE" delete \
- ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa \
- -l release="$CI_ENVIRONMENT_SLUG" \
- || true
-}
-
-function install_external_dns() {
- local release_name="dns-gitlab-review-app"
- local domain=$(echo "${REVIEW_APPS_DOMAIN}" | awk -F. '{printf "%s.%s", $(NF-1), $NF}')
-
- if ! deployExists "${KUBE_NAMESPACE}" "${release_name}" || previousDeployFailed "${release_name}" ; then
- echo "Installing external-dns helm chart"
- helm repo update
- helm install stable/external-dns \
- -n "${release_name}" \
- --namespace "${KUBE_NAMESPACE}" \
- --set provider="aws" \
- --set aws.secretKey="${REVIEW_APPS_AWS_SECRET_KEY}" \
- --set aws.accessKey="${REVIEW_APPS_AWS_ACCESS_KEY}" \
- --set aws.zoneType="public" \
- --set domainFilters[0]="${domain}" \
- --set txtOwnerId="${KUBE_NAMESPACE}" \
- --set rbac.create="true" \
- --set policy="sync"
- fi
-}
-
-function get_pod() {
- local app_name="${1}"
- local status="${2-Running}"
- get_pod_cmd="kubectl get pods -n ${KUBE_NAMESPACE} --field-selector=status.phase=${status} -lapp=${app_name},release=${CI_ENVIRONMENT_SLUG} --no-headers -o=custom-columns=NAME:.metadata.name"
- echoinfo "Running '${get_pod_cmd}'"
-
- while true; do
- local pod_name="$(eval $get_pod_cmd)"
- [[ "${pod_name}" == "" ]] || break
-
- echoinfo "Waiting till '${app_name}' pod is ready";
- sleep 5;
- done
-
- echoinfo "The pod name is '${pod_name}'."
- echo "${pod_name}"
-}
-
function add_license() {
if [ -z "${REVIEW_APPS_EE_LICENSE}" ]; then echo "License not found" && return; fi
task_runner_pod=$(get_pod "task-runner");
if [ -z "${task_runner_pod}" ]; then echo "Task runner pod not found" && return; fi
+ echoinfo "Installing license..." true
+
echo "${REVIEW_APPS_EE_LICENSE}" > /tmp/license.gitlab
kubectl -n "$KUBE_NAMESPACE" cp /tmp/license.gitlab ${task_runner_pod}:/tmp/license.gitlab
rm /tmp/license.gitlab
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 79f97aa4170..c8fa93a74ee 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -86,6 +86,10 @@ describe Projects::MergeRequestsController do
end
describe 'as json' do
+ before do
+ expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
+ end
+
context 'with basic serializer param' do
it 'renders basic MR entity as json' do
go(serializer: 'basic', format: :json)
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index 1cc3c0e03d8..97405ec7c58 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -3,6 +3,7 @@ FactoryBot.define do
user
name 'test-cluster'
cluster_type :project_type
+ managed true
trait :instance do
cluster_type { Clusters::Cluster.cluster_types[:instance_type] }
@@ -63,5 +64,9 @@ FactoryBot.define do
trait :with_domain do
domain 'example.com'
end
+
+ trait :user_managed do
+ managed false
+ end
end
end
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index a1809a26265..abf0e6bccb7 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -117,9 +117,20 @@ FactoryBot.define do
end
end
+ trait :with_legacy_detached_merge_request_pipeline do
+ after(:create) do |merge_request|
+ merge_request.merge_request_pipelines << create(:ci_pipeline,
+ source: :merge_request_event,
+ merge_request: merge_request,
+ project: merge_request.source_project,
+ ref: merge_request.source_branch,
+ sha: merge_request.source_branch_sha)
+ end
+ end
+
trait :with_detached_merge_request_pipeline do
- after(:build) do |merge_request|
- merge_request.merge_request_pipelines << build(:ci_pipeline,
+ after(:create) do |merge_request|
+ merge_request.merge_request_pipelines << create(:ci_pipeline,
source: :merge_request_event,
merge_request: merge_request,
project: merge_request.source_project,
@@ -135,7 +146,7 @@ FactoryBot.define do
target_sha { target_branch_sha }
end
- after(:build) do |merge_request, evaluator|
+ after(:create) do |merge_request, evaluator|
merge_request.merge_request_pipelines << create(:ci_pipeline,
source: :merge_request_event,
merge_request: merge_request,
diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb
index b9fc52d0dce..d2e46d15730 100644
--- a/spec/features/clusters/cluster_detail_page_spec.rb
+++ b/spec/features/clusters/cluster_detail_page_spec.rb
@@ -53,12 +53,80 @@ describe 'Clusterable > Show page' do
end
end
+ shared_examples 'editing a GCP cluster' do
+ before do
+ clusterable.add_maintainer(current_user)
+ visit cluster_path
+ end
+
+ it 'is not able to edit the name, API url, CA certificate nor token' do
+ within('#js-cluster-details') do
+ cluster_name_field = find('.cluster-name')
+ api_url_field = find('#cluster_platform_kubernetes_attributes_api_url')
+ ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert')
+ token_field = find('#cluster_platform_kubernetes_attributes_token')
+
+ expect(cluster_name_field).to be_readonly
+ expect(api_url_field).to be_readonly
+ expect(ca_certificate_field).to be_readonly
+ expect(token_field).to be_readonly
+ end
+ end
+
+ it 'displays GKE information' do
+ within('#advanced-settings-section') do
+ expect(page).to have_content('Google Kubernetes Engine')
+ expect(page).to have_content('Manage your Kubernetes cluster by visiting')
+ end
+ end
+ end
+
+ shared_examples 'editing a user-provided cluster' do
+ before do
+ clusterable.add_maintainer(current_user)
+ visit cluster_path
+ end
+
+ it 'is able to edit the name, API url, CA certificate and token' do
+ within('#js-cluster-details') do
+ cluster_name_field = find('#cluster_name')
+ api_url_field = find('#cluster_platform_kubernetes_attributes_api_url')
+ ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert')
+ token_field = find('#cluster_platform_kubernetes_attributes_token')
+
+ expect(cluster_name_field).not_to be_readonly
+ expect(api_url_field).not_to be_readonly
+ expect(ca_certificate_field).not_to be_readonly
+ expect(token_field).not_to be_readonly
+ end
+ end
+
+ it 'does not display GKE information' do
+ within('#advanced-settings-section') do
+ expect(page).not_to have_content('Google Kubernetes Engine')
+ expect(page).not_to have_content('Manage your Kubernetes cluster by visiting')
+ end
+ end
+ end
+
context 'when clusterable is a project' do
it_behaves_like 'editing domain' do
let(:clusterable) { create(:project) }
let(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [clusterable]) }
let(:cluster_path) { project_cluster_path(clusterable, cluster) }
end
+
+ it_behaves_like 'editing a GCP cluster' do
+ let(:clusterable) { create(:project) }
+ let(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [clusterable]) }
+ let(:cluster_path) { project_cluster_path(clusterable, cluster) }
+ end
+
+ it_behaves_like 'editing a user-provided cluster' do
+ let(:clusterable) { create(:project) }
+ let(:cluster) { create(:cluster, :provided_by_user, :project, projects: [clusterable]) }
+ let(:cluster_path) { project_cluster_path(clusterable, cluster) }
+ end
end
context 'when clusterable is a group' do
@@ -67,5 +135,17 @@ describe 'Clusterable > Show page' do
let(:cluster) { create(:cluster, :provided_by_gcp, :group, groups: [clusterable]) }
let(:cluster_path) { group_cluster_path(clusterable, cluster) }
end
+
+ it_behaves_like 'editing a GCP cluster' do
+ let(:clusterable) { create(:group) }
+ let(:cluster) { create(:cluster, :provided_by_gcp, :group, groups: [clusterable]) }
+ let(:cluster_path) { group_cluster_path(clusterable, cluster) }
+ end
+
+ it_behaves_like 'editing a user-provided cluster' do
+ let(:clusterable) { create(:group) }
+ let(:cluster) { create(:cluster, :provided_by_user, :group, groups: [clusterable]) }
+ let(:cluster_path) { group_cluster_path(clusterable, cluster) }
+ end
end
end
diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb
index b5e7c3954e2..362f8a468ec 100644
--- a/spec/features/issues/user_uses_quick_actions_spec.rb
+++ b/spec/features/issues/user_uses_quick_actions_spec.rb
@@ -3,8 +3,41 @@ require 'rails_helper'
describe 'Issues > User uses quick actions', :js do
include Spec::Support::Helpers::Features::NotesHelpers
- it_behaves_like 'issuable record that supports quick actions in its description and notes', :issue do
+ context "issuable common quick actions" do
+ let(:new_url_opts) { {} }
+ let(:maintainer) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let!(:label_bug) { create(:label, project: project, title: 'bug') }
+ let!(:label_feature) { create(:label, project: project, title: 'feature') }
+ let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
let(:issuable) { create(:issue, project: project) }
+ let(:source_issuable) { create(:issue, project: project, milestone: milestone, labels: [label_bug, label_feature])}
+
+ it_behaves_like 'assign quick action', :issue
+ it_behaves_like 'unassign quick action', :issue
+ it_behaves_like 'close quick action', :issue
+ it_behaves_like 'reopen quick action', :issue
+ it_behaves_like 'title quick action', :issue
+ it_behaves_like 'todo quick action', :issue
+ it_behaves_like 'done quick action', :issue
+ it_behaves_like 'subscribe quick action', :issue
+ it_behaves_like 'unsubscribe quick action', :issue
+ it_behaves_like 'lock quick action', :issue
+ it_behaves_like 'unlock quick action', :issue
+ it_behaves_like 'milestone quick action', :issue
+ it_behaves_like 'remove_milestone quick action', :issue
+ it_behaves_like 'label quick action', :issue
+ it_behaves_like 'unlabel quick action', :issue
+ it_behaves_like 'relabel quick action', :issue
+ it_behaves_like 'award quick action', :issue
+ it_behaves_like 'estimate quick action', :issue
+ it_behaves_like 'remove_estimate quick action', :issue
+ it_behaves_like 'spend quick action', :issue
+ it_behaves_like 'remove_time_spent quick action', :issue
+ it_behaves_like 'shrug quick action', :issue
+ it_behaves_like 'tableflip quick action', :issue
+ it_behaves_like 'copy_metadata quick action', :issue
+ it_behaves_like 'issuable time tracker', :issue
end
describe 'issue-only commands' do
@@ -15,37 +48,17 @@ describe 'Issues > User uses quick actions', :js do
project.add_maintainer(user)
sign_in(user)
visit project_issue_path(project, issue)
+ wait_for_all_requests
end
after do
wait_for_requests
end
- describe 'time tracking' do
- let(:issue) { create(:issue, project: project) }
-
- before do
- visit project_issue_path(project, issue)
- end
-
- it_behaves_like 'issuable time tracker'
- end
-
describe 'adding a due date from note' do
let(:issue) { create(:issue, project: project) }
- context 'when the current user can update the due date' do
- it 'does not create a note, and sets the due date accordingly' do
- add_note("/due 2016-08-28")
-
- expect(page).not_to have_content '/due 2016-08-28'
- expect(page).to have_content 'Commands applied'
-
- issue.reload
-
- expect(issue.due_date).to eq Date.new(2016, 8, 28)
- end
- end
+ it_behaves_like 'due quick action available and date can be added'
context 'when the current user cannot update the due date' do
let(:guest) { create(:user) }
@@ -56,35 +69,14 @@ describe 'Issues > User uses quick actions', :js do
visit project_issue_path(project, issue)
end
- it 'does not create a note, and sets the due date accordingly' do
- add_note("/due 2016-08-28")
-
- expect(page).not_to have_content 'Commands applied'
-
- issue.reload
-
- expect(issue.due_date).to be_nil
- end
+ it_behaves_like 'due quick action not available'
end
end
describe 'removing a due date from note' do
let(:issue) { create(:issue, project: project, due_date: Date.new(2016, 8, 28)) }
- context 'when the current user can update the due date' do
- it 'does not create a note, and removes the due date accordingly' do
- expect(issue.due_date).to eq Date.new(2016, 8, 28)
-
- add_note("/remove_due_date")
-
- expect(page).not_to have_content '/remove_due_date'
- expect(page).to have_content 'Commands applied'
-
- issue.reload
-
- expect(issue.due_date).to be_nil
- end
- end
+ it_behaves_like 'remove_due_date action available and due date can be removed'
context 'when the current user cannot update the due date' do
let(:guest) { create(:user) }
@@ -95,15 +87,7 @@ describe 'Issues > User uses quick actions', :js do
visit project_issue_path(project, issue)
end
- it 'does not create a note, and sets the due date accordingly' do
- add_note("/remove_due_date")
-
- expect(page).not_to have_content 'Commands applied'
-
- issue.reload
-
- expect(issue.due_date).to eq Date.new(2016, 8, 28)
- end
+ it_behaves_like 'remove_due_date action not available'
end
end
@@ -200,6 +184,7 @@ describe 'Issues > User uses quick actions', :js do
gitlab_sign_out
sign_in(user)
visit project_issue_path(project, issue)
+ wait_for_requests
end
it 'moves the issue' do
@@ -221,6 +206,7 @@ describe 'Issues > User uses quick actions', :js do
gitlab_sign_out
sign_in(user)
visit project_issue_path(project, issue)
+ wait_for_requests
end
it 'does not move the issue' do
@@ -238,6 +224,7 @@ describe 'Issues > User uses quick actions', :js do
gitlab_sign_out
sign_in(user)
visit project_issue_path(project, issue)
+ wait_for_requests
end
it 'does not move the issue' do
diff --git a/spec/features/merge_request/user_uses_quick_actions_spec.rb b/spec/features/merge_request/user_uses_quick_actions_spec.rb
index b81478a481f..a2b5859bd1e 100644
--- a/spec/features/merge_request/user_uses_quick_actions_spec.rb
+++ b/spec/features/merge_request/user_uses_quick_actions_spec.rb
@@ -9,9 +9,41 @@ describe 'Merge request > User uses quick actions', :js do
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
- it_behaves_like 'issuable record that supports quick actions in its description and notes', :merge_request do
+ context "issuable common quick actions" do
+ let!(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } }
+ let(:maintainer) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+ let!(:label_bug) { create(:label, project: project, title: 'bug') }
+ let!(:label_feature) { create(:label, project: project, title: 'feature') }
+ let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
let(:issuable) { create(:merge_request, source_project: project) }
- let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } }
+ let(:source_issuable) { create(:issue, project: project, milestone: milestone, labels: [label_bug, label_feature])}
+
+ it_behaves_like 'assign quick action', :merge_request
+ it_behaves_like 'unassign quick action', :merge_request
+ it_behaves_like 'close quick action', :merge_request
+ it_behaves_like 'reopen quick action', :merge_request
+ it_behaves_like 'title quick action', :merge_request
+ it_behaves_like 'todo quick action', :merge_request
+ it_behaves_like 'done quick action', :merge_request
+ it_behaves_like 'subscribe quick action', :merge_request
+ it_behaves_like 'unsubscribe quick action', :merge_request
+ it_behaves_like 'lock quick action', :merge_request
+ it_behaves_like 'unlock quick action', :merge_request
+ it_behaves_like 'milestone quick action', :merge_request
+ it_behaves_like 'remove_milestone quick action', :merge_request
+ it_behaves_like 'label quick action', :merge_request
+ it_behaves_like 'unlabel quick action', :merge_request
+ it_behaves_like 'relabel quick action', :merge_request
+ it_behaves_like 'award quick action', :merge_request
+ it_behaves_like 'estimate quick action', :merge_request
+ it_behaves_like 'remove_estimate quick action', :merge_request
+ it_behaves_like 'spend quick action', :merge_request
+ it_behaves_like 'remove_time_spent quick action', :merge_request
+ it_behaves_like 'shrug quick action', :merge_request
+ it_behaves_like 'tableflip quick action', :merge_request
+ it_behaves_like 'copy_metadata quick action', :merge_request
+ it_behaves_like 'issuable time tracker', :merge_request
end
describe 'merge-request-only commands' do
@@ -24,20 +56,12 @@ describe 'Merge request > User uses quick actions', :js do
project.add_maintainer(user)
end
- describe 'time tracking' do
- before do
- sign_in(user)
- visit project_merge_request_path(project, merge_request)
- end
-
- it_behaves_like 'issuable time tracker'
- end
-
describe 'toggling the WIP prefix in the title from note' do
context 'when the current user can toggle the WIP prefix' do
before do
sign_in(user)
visit project_merge_request_path(project, merge_request)
+ wait_for_requests
end
it 'adds the WIP: prefix to the title' do
@@ -135,11 +159,16 @@ describe 'Merge request > User uses quick actions', :js do
visit project_merge_request_path(project, merge_request)
end
- it 'does not recognize the command nor create a note' do
- add_note('/due 2016-08-28')
+ it_behaves_like 'due quick action not available'
+ end
- expect(page).not_to have_content '/due 2016-08-28'
+ describe 'removing a due date from note' do
+ before do
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
end
+
+ it_behaves_like 'remove_due_date action not available'
end
describe '/target_branch command in merge request' do
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 9fdf78baa1e..b197557039d 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -59,11 +59,11 @@ describe 'Pipeline', :js do
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) }
- before do
- visit project_pipeline_path(project, pipeline)
- end
+ subject(:visit_pipeline) { visit project_pipeline_path(project, pipeline) }
it 'shows the pipeline graph' do
+ visit_pipeline
+
expect(page).to have_selector('.pipeline-visualization')
expect(page).to have_content('Build')
expect(page).to have_content('Test')
@@ -73,14 +73,20 @@ describe 'Pipeline', :js do
end
it 'shows Pipeline tab pane as active' do
+ visit_pipeline
+
expect(page).to have_css('#js-tab-pipeline.active')
end
it 'shows link to the pipeline ref' do
+ visit_pipeline
+
expect(page).to have_link(pipeline.ref)
end
it 'shows the pipeline information' do
+ visit_pipeline
+
within '.pipeline-info' do
expect(page).to have_content("#{pipeline.statuses.count} jobs " \
"for #{pipeline.ref} ")
@@ -96,6 +102,10 @@ describe 'Pipeline', :js do
end
describe 'pipeline graph' do
+ before do
+ visit_pipeline
+ end
+
context 'when pipeline has running builds' do
it 'shows a running icon and a cancel action for the running build' do
page.within('#ci-badge-deploy') do
@@ -227,6 +237,10 @@ describe 'Pipeline', :js do
end
context 'page tabs' do
+ before do
+ visit_pipeline
+ end
+
it 'shows Pipeline, Jobs and Failed Jobs tabs with link' do
expect(page).to have_link('Pipeline')
expect(page).to have_link('Jobs')
@@ -253,6 +267,10 @@ describe 'Pipeline', :js do
end
context 'retrying jobs' do
+ before do
+ visit_pipeline
+ end
+
it { expect(page).not_to have_content('retried') }
context 'when retrying' do
@@ -265,6 +283,10 @@ describe 'Pipeline', :js do
end
context 'canceling jobs' do
+ before do
+ visit_pipeline
+ end
+
it { expect(page).not_to have_selector('.ci-canceled') }
context 'when canceling' do
@@ -284,6 +306,10 @@ describe 'Pipeline', :js do
user: user)
end
+ before do
+ visit_pipeline
+ end
+
it 'does not render link to the pipeline ref' do
expect(page).not_to have_link(pipeline.ref)
expect(page).to have_content(pipeline.ref)
@@ -305,6 +331,10 @@ describe 'Pipeline', :js do
merge_request.all_pipelines.last
end
+ before do
+ visit_pipeline
+ end
+
it 'shows the pipeline information' do
within '.pipeline-info' do
expect(page).to have_content("#{pipeline.statuses.count} jobs " \
@@ -356,6 +386,8 @@ describe 'Pipeline', :js do
before do
pipeline.update(user: user)
+
+ visit_pipeline
end
it 'shows the pipeline information' do
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 368a814874f..9d5780d29b0 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -447,7 +447,7 @@ describe 'Login' do
'You can leave Group 1 and leave Group 2. '\
'You need to do this '\
'before '\
- "#{(Time.zone.now + 2.days).strftime("%a, %-d %b %Y %H:%M:%S %z")}"
+ "#{(Time.zone.now + 2.days).strftime("%a, %d %b %Y %H:%M:%S %z")}"
)
end
end
diff --git a/spec/frontend/.eslintrc.yml b/spec/frontend/.eslintrc.yml
index 046215e4c93..054dc27cda6 100644
--- a/spec/frontend/.eslintrc.yml
+++ b/spec/frontend/.eslintrc.yml
@@ -2,8 +2,13 @@
env:
jest/globals: true
plugins:
-- jest
+ - jest
settings:
import/resolver:
jest:
- jestConfigFile: "jest.config.js"
+ jestConfigFile: 'jest.config.js'
+globals:
+ getJSONFixture: false
+ loadFixtures: false
+ preloadFixtures: false
+ setFixtures: false
diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js
index cb128c7d880..34df8019a2e 100644
--- a/spec/frontend/environment.js
+++ b/spec/frontend/environment.js
@@ -6,6 +6,7 @@ const JSDOMEnvironment = require('jest-environment-jsdom');
class CustomEnvironment extends JSDOMEnvironment {
constructor(config, context) {
super(config, context);
+
Object.assign(context.console, {
error(...args) {
throw new ErrorWithStack(
@@ -21,6 +22,30 @@ class CustomEnvironment extends JSDOMEnvironment {
);
},
});
+
+ const { testEnvironmentOptions } = config;
+ this.global.gon = {
+ ee: testEnvironmentOptions.IS_EE,
+ };
+
+ this.rejectedPromises = [];
+
+ this.global.promiseRejectionHandler = error => {
+ this.rejectedPromises.push(error);
+ };
+ }
+
+ async teardown() {
+ await new Promise(setImmediate);
+
+ if (this.rejectedPromises.length > 0) {
+ throw new ErrorWithStack(
+ `Unhandled Promise rejections: ${this.rejectedPromises.join(', ')}`,
+ this.teardown,
+ );
+ }
+
+ await super.teardown();
}
}
diff --git a/spec/frontend/helpers/class_spec_helper.js b/spec/frontend/helpers/class_spec_helper.js
new file mode 100644
index 00000000000..7a60d33b471
--- /dev/null
+++ b/spec/frontend/helpers/class_spec_helper.js
@@ -0,0 +1,9 @@
+export default class ClassSpecHelper {
+ static itShouldBeAStaticMethod(base, method) {
+ return it('should be a static method', () => {
+ expect(Object.prototype.hasOwnProperty.call(base, method)).toBeTruthy();
+ });
+ }
+}
+
+window.ClassSpecHelper = ClassSpecHelper;
diff --git a/spec/frontend/helpers/fixtures.js b/spec/frontend/helpers/fixtures.js
index de9058d7832..f0351aa31c6 100644
--- a/spec/frontend/helpers/fixtures.js
+++ b/spec/frontend/helpers/fixtures.js
@@ -1,5 +1,3 @@
-/* eslint-disable import/prefer-default-export, global-require, import/no-dynamic-require */
-
import fs from 'fs';
import path from 'path';
@@ -7,16 +5,32 @@ import { ErrorWithStack } from 'jest-util';
const fixturesBasePath = path.join(process.cwd(), 'spec', 'javascripts', 'fixtures');
-export function getJSONFixture(relativePath, ee = false) {
- const absolutePath = path.join(fixturesBasePath, ee ? 'ee' : '', relativePath);
+export function getFixture(relativePath) {
+ const absolutePath = path.join(fixturesBasePath, relativePath);
if (!fs.existsSync(absolutePath)) {
throw new ErrorWithStack(
`Fixture file ${relativePath} does not exist.
Did you run bin/rake karma:fixtures?`,
- getJSONFixture,
+ getFixture,
);
}
- return require(absolutePath);
+ return fs.readFileSync(absolutePath, 'utf8');
}
+
+export const getJSONFixture = relativePath => JSON.parse(getFixture(relativePath));
+
+export const resetHTMLFixture = () => {
+ document.body.textContent = '';
+};
+
+export const setHTMLFixture = (htmlContent, resetHook = afterEach) => {
+ document.body.outerHTML = htmlContent;
+ resetHook(resetHTMLFixture);
+};
+
+export const loadHTMLFixture = (relativePath, resetHook = afterEach) => {
+ const fileContent = getFixture(relativePath);
+ setHTMLFixture(fileContent, resetHook);
+};
diff --git a/spec/frontend/helpers/locale_helper.js b/spec/frontend/helpers/locale_helper.js
new file mode 100644
index 00000000000..80047b06003
--- /dev/null
+++ b/spec/frontend/helpers/locale_helper.js
@@ -0,0 +1,11 @@
+/* eslint-disable import/prefer-default-export */
+
+export const setLanguage = languageCode => {
+ const htmlElement = document.querySelector('html');
+
+ if (languageCode) {
+ htmlElement.setAttribute('lang', languageCode);
+ } else {
+ htmlElement.removeAttribute('lang');
+ }
+};
diff --git a/spec/frontend/helpers/scroll_into_view_promise.js b/spec/frontend/helpers/scroll_into_view_promise.js
new file mode 100644
index 00000000000..0edea2103da
--- /dev/null
+++ b/spec/frontend/helpers/scroll_into_view_promise.js
@@ -0,0 +1,28 @@
+export default function scrollIntoViewPromise(intersectionTarget, timeout = 100, maxTries = 5) {
+ return new Promise((resolve, reject) => {
+ let intersectionObserver;
+ let retry = 0;
+
+ const intervalId = setInterval(() => {
+ if (retry >= maxTries) {
+ intersectionObserver.disconnect();
+ clearInterval(intervalId);
+ reject(new Error(`Could not scroll target into viewPort within ${timeout * maxTries} ms`));
+ }
+ retry += 1;
+ intersectionTarget.scrollIntoView();
+ }, timeout);
+
+ intersectionObserver = new IntersectionObserver(entries => {
+ if (entries[0].isIntersecting) {
+ intersectionObserver.disconnect();
+ clearInterval(intervalId);
+ resolve();
+ }
+ });
+
+ intersectionObserver.observe(intersectionTarget);
+
+ intersectionTarget.scrollIntoView();
+ });
+}
diff --git a/spec/frontend/helpers/set_timeout_promise_helper.js b/spec/frontend/helpers/set_timeout_promise_helper.js
new file mode 100644
index 00000000000..47087619187
--- /dev/null
+++ b/spec/frontend/helpers/set_timeout_promise_helper.js
@@ -0,0 +1,4 @@
+export default (time = 0) =>
+ new Promise(resolve => {
+ setTimeout(resolve, time);
+ });
diff --git a/spec/frontend/helpers/user_mock_data_helper.js b/spec/frontend/helpers/user_mock_data_helper.js
new file mode 100644
index 00000000000..6999fa1f8a1
--- /dev/null
+++ b/spec/frontend/helpers/user_mock_data_helper.js
@@ -0,0 +1,14 @@
+export default {
+ createNumberRandomUsers(numberUsers) {
+ const users = [];
+ for (let i = 0; i < numberUsers; i += 1) {
+ users.push({
+ avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: i + 1,
+ name: `GitLab User ${i}`,
+ username: `gitlab${i}`,
+ });
+ }
+ return users;
+ },
+};
diff --git a/spec/frontend/helpers/vue_component_helper.js b/spec/frontend/helpers/vue_component_helper.js
new file mode 100644
index 00000000000..e0fe18e5560
--- /dev/null
+++ b/spec/frontend/helpers/vue_component_helper.js
@@ -0,0 +1,18 @@
+/**
+ * Replaces line break with an empty space
+ * @param {*} data
+ */
+export const removeBreakLine = data => data.replace(/\r?\n|\r/g, ' ');
+
+/**
+ * Removes line breaks, spaces and trims the given text
+ * @param {String} str
+ * @returns {String}
+ */
+export const trimText = str =>
+ str
+ .replace(/\r?\n|\r/g, '')
+ .replace(/\s\s+/g, ' ')
+ .trim();
+
+export const removeWhitespace = str => str.replace(/\s\s+/g, ' ');
diff --git a/spec/frontend/helpers/vue_resource_helper.js b/spec/frontend/helpers/vue_resource_helper.js
new file mode 100644
index 00000000000..0f58af09933
--- /dev/null
+++ b/spec/frontend/helpers/vue_resource_helper.js
@@ -0,0 +1,11 @@
+// eslint-disable-next-line import/prefer-default-export
+export const headersInterceptor = (request, next) => {
+ next(response => {
+ const headers = {};
+ response.headers.forEach((value, key) => {
+ headers[key] = value;
+ });
+ // eslint-disable-next-line no-param-reassign
+ response.headers = headers;
+ });
+};
diff --git a/spec/frontend/helpers/vue_test_utils_helper.js b/spec/frontend/helpers/vue_test_utils_helper.js
new file mode 100644
index 00000000000..19e27388eeb
--- /dev/null
+++ b/spec/frontend/helpers/vue_test_utils_helper.js
@@ -0,0 +1,19 @@
+/* eslint-disable import/prefer-default-export */
+
+const vNodeContainsText = (vnode, text) =>
+ (vnode.text && vnode.text.includes(text)) ||
+ (vnode.children && vnode.children.filter(child => vNodeContainsText(child, text)).length);
+
+/**
+ * Determines whether a `shallowMount` Wrapper contains text
+ * within one of it's slots. This will also work on Wrappers
+ * acquired with `find()`, but only if it's parent Wrapper
+ * was shallowMounted.
+ * NOTE: Prefer checking the rendered output of a component
+ * wherever possible using something like `text()` instead.
+ * @param {Wrapper} shallowWrapper - Vue test utils wrapper (shallowMounted)
+ * @param {String} slotName
+ * @param {String} text
+ */
+export const shallowWrapperContainsSlotText = (shallowWrapper, slotName, text) =>
+ !!shallowWrapper.vm.$slots[slotName].filter(vnode => vNodeContainsText(vnode, text)).length;
diff --git a/spec/frontend/helpers/vuex_action_helper.js b/spec/frontend/helpers/vuex_action_helper.js
new file mode 100644
index 00000000000..88652202a8e
--- /dev/null
+++ b/spec/frontend/helpers/vuex_action_helper.js
@@ -0,0 +1,104 @@
+const noop = () => {};
+
+/**
+ * Helper for testing action with expected mutations inspired in
+ * https://vuex.vuejs.org/en/testing.html
+ *
+ * @param {Function} action to be tested
+ * @param {Object} payload will be provided to the action
+ * @param {Object} state will be provided to the action
+ * @param {Array} [expectedMutations=[]] mutations expected to be committed
+ * @param {Array} [expectedActions=[]] actions expected to be dispatched
+ * @param {Function} [done=noop] to be executed after the tests
+ * @return {Promise}
+ *
+ * @example
+ * testAction(
+ * actions.actionName, // action
+ * { }, // mocked payload
+ * state, //state
+ * // expected mutations
+ * [
+ * { type: types.MUTATION}
+ * { type: types.MUTATION_1, payload: jasmine.any(Number)}
+ * ],
+ * // expected actions
+ * [
+ * { type: 'actionName', payload: {param: 'foobar'}},
+ * { type: 'actionName1'}
+ * ]
+ * done,
+ * );
+ *
+ * @example
+ * testAction(
+ * actions.actionName, // action
+ * { }, // mocked payload
+ * state, //state
+ * [ { type: types.MUTATION} ], // expected mutations
+ * [], // expected actions
+ * ).then(done)
+ * .catch(done.fail);
+ */
+export default (
+ action,
+ payload,
+ state,
+ expectedMutations = [],
+ expectedActions = [],
+ done = noop,
+) => {
+ const mutations = [];
+ const actions = [];
+
+ // mock commit
+ const commit = (type, mutationPayload) => {
+ const mutation = { type };
+
+ if (typeof mutationPayload !== 'undefined') {
+ mutation.payload = mutationPayload;
+ }
+
+ mutations.push(mutation);
+ };
+
+ // mock dispatch
+ const dispatch = (type, actionPayload) => {
+ const dispatchedAction = { type };
+
+ if (typeof actionPayload !== 'undefined') {
+ dispatchedAction.payload = actionPayload;
+ }
+
+ actions.push(dispatchedAction);
+ };
+
+ const validateResults = () => {
+ expect({
+ mutations,
+ actions,
+ }).toEqual({
+ mutations: expectedMutations,
+ actions: expectedActions,
+ });
+ done();
+ };
+
+ const result = action(
+ { commit, state, dispatch, rootState: state, rootGetters: state, getters: state },
+ payload,
+ );
+
+ return new Promise(resolve => {
+ setImmediate(resolve);
+ })
+ .then(() => result)
+ .catch(error => {
+ validateResults();
+ throw error;
+ })
+ .then(data => {
+ validateResults();
+ return data;
+ });
+};
diff --git a/spec/frontend/helpers/wait_for_attribute_change.js b/spec/frontend/helpers/wait_for_attribute_change.js
new file mode 100644
index 00000000000..8f22d569222
--- /dev/null
+++ b/spec/frontend/helpers/wait_for_attribute_change.js
@@ -0,0 +1,16 @@
+export default (domElement, attributes, timeout = 1500) =>
+ new Promise((resolve, reject) => {
+ let observer;
+ const timeoutId = setTimeout(() => {
+ observer.disconnect();
+ reject(new Error(`Could not see an attribute update within ${timeout} ms`));
+ }, timeout);
+
+ observer = new MutationObserver(() => {
+ clearTimeout(timeoutId);
+ observer.disconnect();
+ resolve();
+ });
+
+ observer.observe(domElement, { attributes: true, attributeFilter: attributes });
+ });
diff --git a/spec/frontend/helpers/wait_for_promises.js b/spec/frontend/helpers/wait_for_promises.js
new file mode 100644
index 00000000000..1d2b53fc770
--- /dev/null
+++ b/spec/frontend/helpers/wait_for_promises.js
@@ -0,0 +1 @@
+export default () => new Promise(resolve => requestAnimationFrame(resolve));
diff --git a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js
index f7637964c60..1e0bc708c31 100644
--- a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js
+++ b/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js
@@ -16,9 +16,9 @@ describe('Abuse Reports', () => {
preloadFixtures(FIXTURE);
- beforeEach(function() {
+ beforeEach(() => {
loadFixtures(FIXTURE);
- this.abuseReports = new AbuseReports();
+ new AbuseReports(); // eslint-disable-line no-new
$messages = $('.abuse-reports .message');
});
diff --git a/spec/javascripts/reports/components/report_section_spec.js b/spec/frontend/reports/components/report_section_spec.js
index b02af8baaec..3b609484b9e 100644
--- a/spec/javascripts/reports/components/report_section_spec.js
+++ b/spec/frontend/reports/components/report_section_spec.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import reportSection from '~/reports/components/report_section.vue';
-import mountComponent, { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper';
+import mountComponent, { mountComponentWithSlots } from 'helpers/vue_mount_component_helper';
describe('Report section', () => {
let vm;
diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js
index 006fc60ef57..c57e0e7cfc6 100644
--- a/spec/frontend/test_setup.js
+++ b/spec/frontend/test_setup.js
@@ -1,12 +1,19 @@
import Vue from 'vue';
+import * as jqueryMatchers from 'custom-jquery-matchers';
import Translate from '~/vue_shared/translate';
import axios from '~/lib/utils/axios_utils';
import { initializeTestTimeout } from './helpers/timeout';
+import { getJSONFixture, loadHTMLFixture, setHTMLFixture } from './helpers/fixtures';
-// wait for pending setTimeout()s
-afterEach(() => {
- jest.runAllTimers();
-});
+process.on('unhandledRejection', global.promiseRejectionHandler);
+
+afterEach(() =>
+ // give Promises a bit more time so they fail the right test
+ new Promise(setImmediate).then(() => {
+ // wait for pending setTimeout()s
+ jest.runAllTimers();
+ }),
+);
initializeTestTimeout(300);
@@ -22,4 +29,31 @@ beforeEach(done => {
done();
});
+Vue.config.devtools = false;
+Vue.config.productionTip = false;
+
Vue.use(Translate);
+
+// workaround for JSDOM not supporting innerText
+// see https://github.com/jsdom/jsdom/issues/1245
+Object.defineProperty(global.Element.prototype, 'innerText', {
+ get() {
+ return this.textContent;
+ },
+ configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
+});
+
+// convenience wrapper for migration from Karma
+Object.assign(global, {
+ loadFixtures: loadHTMLFixture,
+ loadJSONFixtures: getJSONFixture,
+ preloadFixtures() {},
+ setFixtures: setHTMLFixture,
+});
+
+// custom-jquery-matchers was written for an old Jest version, we need to make it compatible
+Object.entries(jqueryMatchers).forEach(([matcherName, matcherFactory]) => {
+ expect.extend({
+ [matcherName]: matcherFactory().compare,
+ });
+});
diff --git a/spec/graphql/types/permission_types/issue_spec.rb b/spec/graphql/types/permission_types/issue_spec.rb
index c3f84629aa2..f0fbeda202f 100644
--- a/spec/graphql/types/permission_types/issue_spec.rb
+++ b/spec/graphql/types/permission_types/issue_spec.rb
@@ -7,6 +7,8 @@ describe Types::PermissionTypes::Issue do
:create_note, :reopen_issue
]
- expect(described_class).to have_graphql_fields(expected_permissions)
+ expected_permissions.each do |permission|
+ expect(described_class).to have_graphql_field(permission)
+ end
end
end
diff --git a/spec/graphql/types/permission_types/project_spec.rb b/spec/graphql/types/permission_types/project_spec.rb
index 4288412eda3..4974995b587 100644
--- a/spec/graphql/types/permission_types/project_spec.rb
+++ b/spec/graphql/types/permission_types/project_spec.rb
@@ -13,6 +13,8 @@ describe Types::PermissionTypes::Project do
:update_wiki, :destroy_wiki, :create_pages, :destroy_pages, :read_pages_content
]
- expect(described_class).to have_graphql_fields(expected_permissions)
+ expected_permissions.each do |permission|
+ expect(described_class).to have_graphql_field(permission)
+ end
end
end
diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb
index 8d717b968dd..a3511e078ce 100644
--- a/spec/helpers/appearances_helper_spec.rb
+++ b/spec/helpers/appearances_helper_spec.rb
@@ -65,12 +65,10 @@ describe AppearancesHelper do
end
describe '#brand_title' do
- it 'returns the default CE title when no appearance is present' do
- allow(helper)
- .to receive(:current_appearance)
- .and_return(nil)
+ it 'returns the default title when no appearance is present' do
+ allow(helper).to receive(:current_appearance).and_return(nil)
- expect(helper.brand_title).to eq('GitLab Community Edition')
+ expect(helper.brand_title).to eq(helper.default_brand_title)
end
end
end
diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb
index 2ba8b3dbf22..aae515def0c 100644
--- a/spec/helpers/auth_helper_spec.rb
+++ b/spec/helpers/auth_helper_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe AuthHelper do
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 540a8674ec2..1763c46389a 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupsHelper do
@@ -227,4 +229,37 @@ describe GroupsHelper do
expect(helper.group_sidebar_links).not_to include(*cross_project_features)
end
end
+
+ describe 'parent_group_options', :nested_groups do
+ let(:current_user) { create(:user) }
+ let(:group) { create(:group, name: 'group') }
+ let(:group2) { create(:group, name: 'group2') }
+
+ before do
+ group.add_owner(current_user)
+ group2.add_owner(current_user)
+ end
+
+ it 'includes explicitly owned groups except self' do
+ expect(parent_group_options(group2)).to eq([{ id: group.id, text: group.human_name }].to_json)
+ end
+
+ it 'excludes parent group' do
+ subgroup = create(:group, parent: group2)
+
+ expect(parent_group_options(subgroup)).to eq([{ id: group.id, text: group.human_name }].to_json)
+ end
+
+ it 'includes subgroups with inherited ownership' do
+ subgroup = create(:group, parent: group)
+
+ expect(parent_group_options(group2)).to eq([{ id: group.id, text: group.human_name }, { id: subgroup.id, text: subgroup.human_name }].to_json)
+ end
+
+ it 'excludes own subgroups' do
+ create(:group, parent: group2)
+
+ expect(parent_group_options(group2)).to eq([{ id: group.id, text: group.human_name }].to_json)
+ end
+ end
end
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 8b82dea2524..1d1446eaa30 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe IssuablesHelper do
@@ -176,7 +178,7 @@ describe IssuablesHelper do
stub_commonmark_sourcepos_disabled
end
- it 'returns the correct json for an issue' do
+ it 'returns the correct data for an issue' do
issue = create(:issue, author: user, description: 'issue text')
@project = issue.project
@@ -198,7 +200,7 @@ describe IssuablesHelper do
initialDescriptionText: 'issue text',
initialTaskStatus: '0 of 0 tasks completed'
}
- expect(helper.issuable_initial_data(issue)).to eq(expected_data)
+ expect(helper.issuable_initial_data(issue)).to match(hash_including(expected_data))
end
end
end
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index 885204062fe..193390d2f2c 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MergeRequestsHelper do
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 291eafece94..37c63807c82 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectsHelper do
diff --git a/spec/javascripts/diffs/components/diff_file_header_spec.js b/spec/javascripts/diffs/components/diff_file_header_spec.js
index e10193c25b7..6614069f44d 100644
--- a/spec/javascripts/diffs/components/diff_file_header_spec.js
+++ b/spec/javascripts/diffs/components/diff_file_header_spec.js
@@ -3,7 +3,7 @@ import Vuex from 'vuex';
import diffsModule from '~/diffs/store/modules';
import notesModule from '~/notes/stores/modules';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
-import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+import mountComponent, { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import diffDiscussionsMockData from '../mock_data/diff_discussions';
import { diffViewerModes } from '~/ide/constants';
@@ -249,6 +249,75 @@ describe('diff_file_header', () => {
expect(vm.$emit).not.toHaveBeenCalled();
});
});
+
+ describe('handleFileNameClick', () => {
+ let e;
+
+ beforeEach(() => {
+ e = { preventDefault: () => {} };
+ spyOn(e, 'preventDefault');
+ });
+
+ describe('when file name links to other page', () => {
+ it('does not call preventDefault if submodule tree url exists', () => {
+ vm = mountComponent(Component, {
+ ...props,
+ diffFile: { ...props.diffFile, submodule_tree_url: 'foobar.com' },
+ });
+
+ vm.handleFileNameClick(e);
+
+ expect(e.preventDefault).not.toHaveBeenCalled();
+ });
+
+ it('does not call preventDefault if submodule_link exists', () => {
+ vm = mountComponent(Component, {
+ ...props,
+ diffFile: { ...props.diffFile, submodule_link: 'foobar.com' },
+ });
+ vm.handleFileNameClick(e);
+
+ expect(e.preventDefault).not.toHaveBeenCalled();
+ });
+
+ it('does not call preventDefault if discussionPath exists', () => {
+ vm = mountComponent(Component, {
+ ...props,
+ discussionPath: 'Foo bar',
+ });
+
+ vm.handleFileNameClick(e);
+
+ expect(e.preventDefault).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('scrolling to diff', () => {
+ let scrollToElement;
+ let el;
+
+ beforeEach(() => {
+ el = document.createElement('div');
+ spyOn(document, 'querySelector').and.returnValue(el);
+ scrollToElement = spyOnDependency(DiffFileHeader, 'scrollToElement');
+ vm = mountComponent(Component, props);
+
+ vm.handleFileNameClick(e);
+ });
+
+ it('calls scrollToElement with file content', () => {
+ expect(scrollToElement).toHaveBeenCalledWith(el);
+ });
+
+ it('element adds the content id to the window location', () => {
+ expect(window.location.hash).toContain(props.diffFile.file_hash);
+ });
+
+ it('calls preventDefault when button does not link to other page', () => {
+ expect(e.preventDefault).toHaveBeenCalled();
+ });
+ });
+ });
});
describe('template', () => {
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index 0bb43c94f6a..2084c36e484 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -2,6 +2,7 @@ import axios from '~/lib/utils/axios_utils';
import * as commonUtils from '~/lib/utils/common_utils';
import MockAdapter from 'axios-mock-adapter';
import { faviconDataUrl, overlayDataUrl, faviconWithOverlayDataUrl } from './mock_data';
+import BreakpointInstance from '~/breakpoints';
const PIXEL_TOLERANCE = 0.2;
@@ -380,6 +381,38 @@ describe('common_utils', () => {
});
});
+ describe('contentTop', () => {
+ it('does not add height for fileTitle or compareVersionsHeader if screen is too small', () => {
+ spyOn(BreakpointInstance, 'getBreakpointSize').and.returnValue('sm');
+
+ setFixtures(`
+ <div class="diff-file file-title-flex-parent">
+ blah blah blah
+ </div>
+ <div class="mr-version-controls">
+ more blah blah blah
+ </div>
+ `);
+
+ expect(commonUtils.contentTop()).toBe(0);
+ });
+
+ it('adds height for fileTitle and compareVersionsHeader screen is large enough', () => {
+ spyOn(BreakpointInstance, 'getBreakpointSize').and.returnValue('lg');
+
+ setFixtures(`
+ <div class="diff-file file-title-flex-parent">
+ blah blah blah
+ </div>
+ <div class="mr-version-controls">
+ more blah blah blah
+ </div>
+ `);
+
+ expect(commonUtils.contentTop()).toBe(18);
+ });
+ });
+
describe('parseBoolean', () => {
const { parseBoolean } = commonUtils;
diff --git a/spec/javascripts/monitoring/charts/area_spec.js b/spec/javascripts/monitoring/charts/area_spec.js
index fb49290be19..549a7935c0f 100644
--- a/spec/javascripts/monitoring/charts/area_spec.js
+++ b/spec/javascripts/monitoring/charts/area_spec.js
@@ -203,6 +203,10 @@ describe('Area component', () => {
.length,
).toBe(data.length);
});
+
+ it('formats line width correctly', () => {
+ expect(chartData[0].lineStyle.width).toBe(2);
+ });
});
describe('scatterSeries', () => {
diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js
index ffc7148fde2..6d4ef960c1a 100644
--- a/spec/javascripts/monitoring/mock_data.js
+++ b/spec/javascripts/monitoring/mock_data.js
@@ -330,6 +330,11 @@ export const metricsGroupsAPIResponse = {
weight: 1,
queries: [
{
+ appearance: {
+ line: {
+ width: 2,
+ },
+ },
query_range:
'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100',
label: 'Core Usage',
diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
index dab0fb51bcc..5181e9c1583 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
@@ -48,6 +48,24 @@ describe Gitlab::Ci::Pipeline::Chain::Command do
end
end
+ describe '#merge_request_ref_exists?' do
+ subject { command.merge_request_ref_exists? }
+
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
+
+ context 'for existing merge request ref' do
+ let(:origin_ref) { merge_request.ref_path }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'for branch ref' do
+ let(:origin_ref) { merge_request.source_branch }
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
describe '#ref' do
subject { command.ref }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
index 8ba56d73838..7d750877d09 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
@@ -10,12 +10,33 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
- project: project, current_user: user, origin_ref: ref)
+ project: project, current_user: user, origin_ref: origin_ref, merge_request: merge_request)
end
let(:step) { described_class.new(pipeline, command) }
let(:ref) { 'master' }
+ let(:origin_ref) { ref }
+ let(:merge_request) { nil }
+
+ shared_context 'detached merge request pipeline' do
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: project,
+ source_branch: ref,
+ target_project: project,
+ target_branch: 'feature')
+ end
+
+ let(:pipeline) do
+ build(:ci_pipeline,
+ source: :merge_request_event,
+ merge_request: merge_request,
+ project: project)
+ end
+
+ let(:origin_ref) { merge_request.ref_path }
+ end
context 'when users has no ability to run a pipeline' do
before do
@@ -58,6 +79,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
it { is_expected.to be_truthy }
+ context 'when pipeline is a detached merge request pipeline' do
+ include_context 'detached merge request pipeline'
+
+ it { is_expected.to be_truthy }
+ end
+
context 'when the branch is protected' do
let!(:protected_branch) do
create(:protected_branch, project: project, name: ref)
@@ -65,6 +92,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
it { is_expected.to be_falsey }
+ context 'when pipeline is a detached merge request pipeline' do
+ include_context 'detached merge request pipeline'
+
+ it { is_expected.to be_falsey }
+ end
+
context 'when developers are allowed to merge' do
let!(:protected_branch) do
create(:protected_branch,
@@ -74,6 +107,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
end
it { is_expected.to be_truthy }
+
+ context 'when pipeline is a detached merge request pipeline' do
+ include_context 'detached merge request pipeline'
+
+ it { is_expected.to be_truthy }
+ end
end
end
@@ -112,6 +151,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
end
it { is_expected.to be_truthy }
+
+ context 'when pipeline is a detached merge request pipeline' do
+ include_context 'detached merge request pipeline'
+
+ it { is_expected.to be_truthy }
+ end
end
context 'when the tag is protected' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
index a7cad423d09..2e8c9d70098 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
@@ -42,6 +42,25 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do
end
end
+ context 'when origin ref is a merge request ref' do
+ let(:command) do
+ Gitlab::Ci::Pipeline::Chain::Command.new(
+ project: project, current_user: user, origin_ref: origin_ref, checkout_sha: checkout_sha)
+ end
+
+ let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
+ let(:origin_ref) { merge_request.ref_path }
+ let(:checkout_sha) { project.repository.commit(merge_request.ref_path).id }
+
+ it 'does not break the chain' do
+ expect(step.break?).to be false
+ end
+
+ it 'does not append pipeline errors' do
+ expect(pipeline.errors).to be_empty
+ end
+ end
+
context 'when ref is ambiguous' do
let(:project) do
create(:project, :repository).tap do |proj|
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index 17d5eae24f5..909dbffa38f 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -115,9 +115,8 @@ describe Gitlab::CurrentSettings do
shared_examples 'a non-persisted ApplicationSetting object' do
let(:current_settings) { described_class.current_application_settings }
- it 'returns a non-persisted ApplicationSetting object' do
- expect(current_settings).to be_a(ApplicationSetting)
- expect(current_settings).not_to be_persisted
+ it 'returns a FakeApplicationSettings object' do
+ expect(current_settings).to be_a(Gitlab::FakeApplicationSettings)
end
it 'uses the default value from ApplicationSetting.defaults' do
@@ -146,6 +145,16 @@ describe Gitlab::CurrentSettings do
it 'uses the value from the DB attribute if present and not overridden by an accessor' do
expect(current_settings.home_page_url).to eq(db_settings.home_page_url)
end
+
+ context 'when a new column is used before being migrated' do
+ before do
+ allow(ApplicationSetting).to receive(:defaults).and_return({ foo: 'bar' })
+ end
+
+ it 'uses the default value if present' do
+ expect(current_settings.foo).to eq('bar')
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb
index 429816efec3..88ea98eb1e1 100644
--- a/spec/lib/gitlab/encoding_helper_spec.rb
+++ b/spec/lib/gitlab/encoding_helper_spec.rb
@@ -189,14 +189,23 @@ describe Gitlab::EncodingHelper do
end
end
- describe '#binary_stringio' do
+ describe '#binary_io' do
it 'does not mutate the original string encoding' do
test = 'my-test'
- io_stream = ext_class.binary_stringio(test)
+ io_stream = ext_class.binary_io(test)
expect(io_stream.external_encoding.name).to eq('ASCII-8BIT')
expect(test.encoding.name).to eq('UTF-8')
end
+
+ it 'returns a copy of the IO with the correct encoding' do
+ test = fixture_file_upload('spec/fixtures/doc_sample.txt').to_io
+
+ io_stream = ext_class.binary_io(test)
+
+ expect(io_stream.external_encoding.name).to eq('ASCII-8BIT')
+ expect(test).not_to eq(io_stream)
+ end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index d7bd757149d..6d6107ca3e7 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -221,6 +221,21 @@ describe Gitlab::GitalyClient::CommitService do
expect(commit).to eq(commit_dbl)
end
end
+
+ context 'when caching of the ref name is enabled' do
+ it 'returns a cached commit' do
+ expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:find_commit).once.and_return(double(commit: commit_dbl))
+
+ commit = nil
+ 2.times do
+ ::Gitlab::GitalyClient.allow_ref_name_caching do
+ commit = described_class.new(repository).find_commit('master')
+ end
+ end
+
+ expect(commit).to eq(commit_dbl)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/quick_actions/command_definition_spec.rb b/spec/lib/gitlab/quick_actions/command_definition_spec.rb
index 136cfb5bcc5..b6e0adbc1c2 100644
--- a/spec/lib/gitlab/quick_actions/command_definition_spec.rb
+++ b/spec/lib/gitlab/quick_actions/command_definition_spec.rb
@@ -69,6 +69,36 @@ describe Gitlab::QuickActions::CommandDefinition do
expect(subject.available?(opts)).to be true
end
end
+
+ context "when the command has types" do
+ before do
+ subject.types = [Issue, Commit]
+ end
+
+ context "when the command target type is allowed" do
+ it "returns true" do
+ opts[:quick_action_target] = Issue.new
+ expect(subject.available?(opts)).to be true
+ end
+ end
+
+ context "when the command target type is not allowed" do
+ it "returns true" do
+ opts[:quick_action_target] = MergeRequest.new
+ expect(subject.available?(opts)).to be false
+ end
+ end
+ end
+
+ context "when the command has no types" do
+ it "any target type is allowed" do
+ opts[:quick_action_target] = Issue.new
+ expect(subject.available?(opts)).to be true
+
+ opts[:quick_action_target] = MergeRequest.new
+ expect(subject.available?(opts)).to be true
+ end
+ end
end
describe "#execute" do
diff --git a/spec/lib/gitlab/quick_actions/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb
index fd4df8694ba..185adab1ff6 100644
--- a/spec/lib/gitlab/quick_actions/dsl_spec.rb
+++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb
@@ -48,13 +48,19 @@ describe Gitlab::QuickActions::Dsl do
substitution :something do |text|
"#{text} Some complicated thing you want in here"
end
+
+ desc 'A command with types'
+ types Issue, Commit
+ command :has_types do
+ "Has Issue and Commit types"
+ end
end
end
describe '.command_definitions' do
it 'returns an array with commands definitions' do
no_args_def, explanation_with_aliases_def, dynamic_description_def,
- cc_def, cond_action_def, with_params_parsing_def, substitution_def =
+ cc_def, cond_action_def, with_params_parsing_def, substitution_def, has_types =
DummyClass.command_definitions
expect(no_args_def.name).to eq(:no_args)
@@ -63,6 +69,7 @@ describe Gitlab::QuickActions::Dsl do
expect(no_args_def.explanation).to eq('')
expect(no_args_def.params).to eq([])
expect(no_args_def.condition_block).to be_nil
+ expect(no_args_def.types).to eq([])
expect(no_args_def.action_block).to be_a_kind_of(Proc)
expect(no_args_def.parse_params_block).to be_nil
expect(no_args_def.warning).to eq('')
@@ -73,6 +80,7 @@ describe Gitlab::QuickActions::Dsl do
expect(explanation_with_aliases_def.explanation).to eq('Static explanation')
expect(explanation_with_aliases_def.params).to eq(['The first argument'])
expect(explanation_with_aliases_def.condition_block).to be_nil
+ expect(explanation_with_aliases_def.types).to eq([])
expect(explanation_with_aliases_def.action_block).to be_a_kind_of(Proc)
expect(explanation_with_aliases_def.parse_params_block).to be_nil
expect(explanation_with_aliases_def.warning).to eq('Possible problem!')
@@ -83,6 +91,7 @@ describe Gitlab::QuickActions::Dsl do
expect(dynamic_description_def.explanation).to eq('')
expect(dynamic_description_def.params).to eq(['The first argument', 'The second argument'])
expect(dynamic_description_def.condition_block).to be_nil
+ expect(dynamic_description_def.types).to eq([])
expect(dynamic_description_def.action_block).to be_a_kind_of(Proc)
expect(dynamic_description_def.parse_params_block).to be_nil
expect(dynamic_description_def.warning).to eq('')
@@ -93,6 +102,7 @@ describe Gitlab::QuickActions::Dsl do
expect(cc_def.explanation).to eq('')
expect(cc_def.params).to eq([])
expect(cc_def.condition_block).to be_nil
+ expect(cc_def.types).to eq([])
expect(cc_def.action_block).to be_nil
expect(cc_def.parse_params_block).to be_nil
expect(cc_def.warning).to eq('')
@@ -103,6 +113,7 @@ describe Gitlab::QuickActions::Dsl do
expect(cond_action_def.explanation).to be_a_kind_of(Proc)
expect(cond_action_def.params).to eq([])
expect(cond_action_def.condition_block).to be_a_kind_of(Proc)
+ expect(cond_action_def.types).to eq([])
expect(cond_action_def.action_block).to be_a_kind_of(Proc)
expect(cond_action_def.parse_params_block).to be_nil
expect(cond_action_def.warning).to eq('')
@@ -113,6 +124,7 @@ describe Gitlab::QuickActions::Dsl do
expect(with_params_parsing_def.explanation).to eq('')
expect(with_params_parsing_def.params).to eq([])
expect(with_params_parsing_def.condition_block).to be_nil
+ expect(with_params_parsing_def.types).to eq([])
expect(with_params_parsing_def.action_block).to be_a_kind_of(Proc)
expect(with_params_parsing_def.parse_params_block).to be_a_kind_of(Proc)
expect(with_params_parsing_def.warning).to eq('')
@@ -123,9 +135,21 @@ describe Gitlab::QuickActions::Dsl do
expect(substitution_def.explanation).to eq('')
expect(substitution_def.params).to eq(['<Comment>'])
expect(substitution_def.condition_block).to be_nil
+ expect(substitution_def.types).to eq([])
expect(substitution_def.action_block.call('text')).to eq('text Some complicated thing you want in here')
expect(substitution_def.parse_params_block).to be_nil
expect(substitution_def.warning).to eq('')
+
+ expect(has_types.name).to eq(:has_types)
+ expect(has_types.aliases).to eq([])
+ expect(has_types.description).to eq('A command with types')
+ expect(has_types.explanation).to eq('')
+ expect(has_types.params).to eq([])
+ expect(has_types.condition_block).to be_nil
+ expect(has_types.types).to eq([Issue, Commit])
+ expect(has_types.action_block).to be_a_kind_of(Proc)
+ expect(has_types.parse_params_block).to be_nil
+ expect(has_types.warning).to eq('')
end
end
end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index 8232715d00e..767b5779a79 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab do
end
describe '.revision' do
- let(:cmd) { %W[#{described_class.config.git.bin_path} log --pretty=format:%h -n 1] }
+ let(:cmd) { %W[#{described_class.config.git.bin_path} log --pretty=format:%h --abbrev=11 -n 1] }
around do |example|
described_class.instance_variable_set(:@_revision, nil)
diff --git a/spec/lib/sentry/client_spec.rb b/spec/lib/sentry/client_spec.rb
index 88e7e2e5ebb..3333f8307ae 100644
--- a/spec/lib/sentry/client_spec.rb
+++ b/spec/lib/sentry/client_spec.rb
@@ -65,7 +65,9 @@ describe Sentry::Client do
let(:issue_status) { 'unresolved' }
let(:limit) { 20 }
- let!(:sentry_api_request) { stub_sentry_request(sentry_url + '/issues/?limit=20&query=is:unresolved', body: issues_sample_response) }
+ let(:sentry_api_response) { issues_sample_response }
+
+ let!(:sentry_api_request) { stub_sentry_request(sentry_url + '/issues/?limit=20&query=is:unresolved', body: sentry_api_response) }
subject { client.list_issues(issue_status: issue_status, limit: limit) }
@@ -74,6 +76,14 @@ describe Sentry::Client do
it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Error
it_behaves_like 'has correct length', 1
+ shared_examples 'has correct external_url' do
+ context 'external_url' do
+ it 'is constructed correctly' do
+ expect(subject[0].external_url).to eq('https://sentrytest.gitlab.com/sentry-org/sentry-project/issues/11')
+ end
+ end
+ end
+
context 'error object created from sentry response' do
using RSpec::Parameterized::TableSyntax
@@ -96,14 +106,10 @@ describe Sentry::Client do
end
with_them do
- it { expect(subject[0].public_send(error_object)).to eq(issues_sample_response[0].dig(*sentry_response)) }
+ it { expect(subject[0].public_send(error_object)).to eq(sentry_api_response[0].dig(*sentry_response)) }
end
- context 'external_url' do
- it 'is constructed correctly' do
- expect(subject[0].external_url).to eq('https://sentrytest.gitlab.com/sentry-org/sentry-project/issues/11')
- end
- end
+ it_behaves_like 'has correct external_url'
end
context 'redirects' do
@@ -135,12 +141,42 @@ describe Sentry::Client do
expect(valid_req_stub).to have_been_requested
end
end
+
+ context 'Older sentry versions where keys are not present' do
+ let(:sentry_api_response) do
+ issues_sample_response[0...1].map do |issue|
+ issue[:project].delete(:id)
+ issue
+ end
+ end
+
+ it_behaves_like 'calls sentry api'
+
+ it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Error
+ it_behaves_like 'has correct length', 1
+
+ it_behaves_like 'has correct external_url'
+ end
+
+ context 'essential keys missing in API response' do
+ let(:sentry_api_response) do
+ issues_sample_response[0...1].map do |issue|
+ issue.except(:id)
+ end
+ end
+
+ it 'raises exception' do
+ expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"')
+ end
+ end
end
describe '#list_projects' do
let(:sentry_list_projects_url) { 'https://sentrytest.gitlab.com/api/0/projects/' }
- let!(:sentry_api_request) { stub_sentry_request(sentry_list_projects_url, body: projects_sample_response) }
+ let(:sentry_api_response) { projects_sample_response }
+
+ let!(:sentry_api_request) { stub_sentry_request(sentry_list_projects_url, body: sentry_api_response) }
subject { client.list_projects }
@@ -149,14 +185,31 @@ describe Sentry::Client do
it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project
it_behaves_like 'has correct length', 2
- context 'keys missing in API response' do
- it 'raises exception' do
- projects_sample_response[0].delete(:slug)
+ context 'essential keys missing in API response' do
+ let(:sentry_api_response) do
+ projects_sample_response[0...1].map do |project|
+ project.except(:slug)
+ end
+ end
- stub_sentry_request(sentry_list_projects_url, body: projects_sample_response)
+ it 'raises exception' do
+ expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "slug"')
+ end
+ end
- expect { subject }.to raise_error(Sentry::Client::SentryError, 'Sentry API response is missing keys. key not found: "slug"')
+ context 'optional keys missing in sentry response' do
+ let(:sentry_api_response) do
+ projects_sample_response[0...1].map do |project|
+ project[:organization].delete(:id)
+ project.delete(:id)
+ project.except(:status)
+ end
end
+
+ it_behaves_like 'calls sentry api'
+
+ it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project
+ it_behaves_like 'has correct length', 1
end
context 'error object created from sentry response' do
@@ -173,7 +226,11 @@ describe Sentry::Client do
end
with_them do
- it { expect(subject[0].public_send(sentry_project_object)).to eq(projects_sample_response[0].dig(*sentry_response)) }
+ it do
+ expect(subject[0].public_send(sentry_project_object)).to(
+ eq(sentry_api_response[0].dig(*sentry_response))
+ )
+ end
end
end
diff --git a/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb
index b2d8f476bb2..a1f243651b5 100644
--- a/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb
+++ b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb
@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20181219145520_migrate_cluster_co
describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers
+ include StubWorker
context 'when there are jobs in the queue' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1])
- stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
described_class.new.up
@@ -19,12 +20,12 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1])
- stubbed_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1])
- stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1])
- stubbed_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1])
- stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1])
- stubbed_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1])
described_class.new.up
@@ -39,7 +40,7 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
+ stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
described_class.new.down
@@ -58,11 +59,4 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error
end
end
-
- def stubbed_worker(queue:)
- Class.new do
- include Sidekiq::Worker
- sidekiq_options queue: queue
- end
- end
end
diff --git a/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb b/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb
index c18ae3b76d3..66555118a43 100644
--- a/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb
+++ b/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb
@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180306074045_migrate_create_tra
describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers
+ include StubWorker
context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
described_class.new.up
@@ -19,11 +20,11 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.up
@@ -37,7 +38,7 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
described_class.new.down
@@ -56,11 +57,4 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error
end
end
-
- def stubbed_worker(queue:)
- Class.new do
- include Sidekiq::Worker
- sidekiq_options queue: queue
- end
- end
end
diff --git a/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb b/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb
index 1ee6c440cf4..6ce04805e5d 100644
--- a/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb
+++ b/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb
@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180603190921_migrate_object_sto
describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers
+ include StubWorker
context 'when there are jobs in the queue' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'object_storage_upload').perform_async('Something', [1])
- stubbed_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1])
+ stub_worker(queue: 'object_storage_upload').perform_async('Something', [1])
+ stub_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1])
described_class.new.up
@@ -23,11 +24,4 @@ describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.up }.not_to raise_error
end
end
-
- def stubbed_worker(queue:)
- Class.new do
- include Sidekiq::Worker
- sidekiq_options queue: queue
- end
- end
end
diff --git a/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb b/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb
index e02bcd2f4da..e38044ccceb 100644
--- a/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb
+++ b/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb
@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20170822101017_migrate_pipeline_s
describe MigratePipelineSidekiqQueues, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers
+ include StubWorker
context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: :pipeline).perform_async('Something', [1])
- stubbed_worker(queue: :build).perform_async('Something', [1])
+ stub_worker(queue: :pipeline).perform_async('Something', [1])
+ stub_worker(queue: :build).perform_async('Something', [1])
described_class.new.up
@@ -20,10 +21,10 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: :pipeline_default).perform_async('Class', [1])
- stubbed_worker(queue: :pipeline_processing).perform_async('Class', [2])
- stubbed_worker(queue: :pipeline_hooks).perform_async('Class', [3])
- stubbed_worker(queue: :pipeline_cache).perform_async('Class', [4])
+ stub_worker(queue: :pipeline_default).perform_async('Class', [1])
+ stub_worker(queue: :pipeline_processing).perform_async('Class', [2])
+ stub_worker(queue: :pipeline_hooks).perform_async('Class', [3])
+ stub_worker(queue: :pipeline_cache).perform_async('Class', [4])
described_class.new.down
@@ -45,11 +46,4 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error
end
end
-
- def stubbed_worker(queue:)
- Class.new do
- include Sidekiq::Worker
- sidekiq_options queue: queue
- end
- end
end
diff --git a/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb b/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb
index f8cf76cb339..94de208e53e 100644
--- a/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb
+++ b/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb
@@ -3,11 +3,12 @@ require Rails.root.join('db', 'post_migrate', '20190124200344_migrate_storage_mi
describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers
+ include StubWorker
context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: :storage_migrator).perform_async(1, 5)
+ stub_worker(queue: :storage_migrator).perform_async(1, 5)
described_class.new.up
@@ -18,7 +19,7 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: :'hashed_storage:hashed_storage_migrator').perform_async(1, 5)
+ stub_worker(queue: :'hashed_storage:hashed_storage_migrator').perform_async(1, 5)
described_class.new.down
@@ -37,11 +38,4 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error
end
end
-
- def stubbed_worker(queue:)
- Class.new do
- include Sidekiq::Worker
- sidekiq_options queue: queue
- end
- end
end
diff --git a/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb b/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb
index 5e3b20ab4a8..976f3ce07d7 100644
--- a/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb
+++ b/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb
@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180307012445_migrate_update_hea
describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers
+ include StubWorker
context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.up
@@ -19,10 +20,10 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis
it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
- stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
described_class.new.up
@@ -35,7 +36,7 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
- stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+ stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.down
@@ -54,11 +55,4 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis
expect { described_class.new.down }.not_to raise_error
end
end
-
- def stubbed_worker(queue:)
- Class.new do
- include Sidekiq::Worker
- sidekiq_options queue: queue
- end
- end
end
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb
index eee80e9bad7..d9d60e02a97 100644
--- a/spec/models/ability_spec.rb
+++ b/spec/models/ability_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ability do
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index f49a61062c1..a5f8e999d5d 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe AbuseReport do
diff --git a/spec/models/active_session_spec.rb b/spec/models/active_session_spec.rb
index e128fe8a4b7..b523f393ece 100644
--- a/spec/models/active_session_spec.rb
+++ b/spec/models/active_session_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
RSpec.describe ActiveSession, :clean_gitlab_redis_shared_state do
diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb
index 3e95aa2b5dd..209d138f956 100644
--- a/spec/models/appearance_spec.rb
+++ b/spec/models/appearance_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Appearance do
diff --git a/spec/models/application_setting/term_spec.rb b/spec/models/application_setting/term_spec.rb
index aa49594f4d1..dd263335b81 100644
--- a/spec/models/application_setting/term_spec.rb
+++ b/spec/models/application_setting/term_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ApplicationSetting::Term do
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 314f0728b8e..c5579dafb4a 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ApplicationSetting do
diff --git a/spec/models/award_emoji_spec.rb b/spec/models/award_emoji_spec.rb
index 3f52091698c..8452ac69734 100644
--- a/spec/models/award_emoji_spec.rb
+++ b/spec/models/award_emoji_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe AwardEmoji do
diff --git a/spec/models/badge_spec.rb b/spec/models/badge_spec.rb
index 33dc19e3432..314d7d1e9f4 100644
--- a/spec/models/badge_spec.rb
+++ b/spec/models/badge_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Badge do
diff --git a/spec/models/badges/group_badge_spec.rb b/spec/models/badges/group_badge_spec.rb
index ed7f83d0489..c297bc957ea 100644
--- a/spec/models/badges/group_badge_spec.rb
+++ b/spec/models/badges/group_badge_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupBadge do
diff --git a/spec/models/badges/project_badge_spec.rb b/spec/models/badges/project_badge_spec.rb
index 0e1a8159cb6..e683d110252 100644
--- a/spec/models/badges/project_badge_spec.rb
+++ b/spec/models/badges/project_badge_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectBadge do
diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb
index 05cf242e84d..d0e1688cce3 100644
--- a/spec/models/blob_spec.rb
+++ b/spec/models/blob_spec.rb
@@ -1,4 +1,6 @@
# encoding: utf-8
+# frozen_string_literal: true
+
require 'rails_helper'
describe Blob do
diff --git a/spec/models/blob_viewer/base_spec.rb b/spec/models/blob_viewer/base_spec.rb
index 7ba28f72215..39c7a34f052 100644
--- a/spec/models/blob_viewer/base_spec.rb
+++ b/spec/models/blob_viewer/base_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::Base do
diff --git a/spec/models/blob_viewer/changelog_spec.rb b/spec/models/blob_viewer/changelog_spec.rb
index db41eca0fc8..0fcc94182af 100644
--- a/spec/models/blob_viewer/changelog_spec.rb
+++ b/spec/models/blob_viewer/changelog_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::Changelog do
diff --git a/spec/models/blob_viewer/composer_json_spec.rb b/spec/models/blob_viewer/composer_json_spec.rb
index 85b0d9668a0..eda34779679 100644
--- a/spec/models/blob_viewer/composer_json_spec.rb
+++ b/spec/models/blob_viewer/composer_json_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::ComposerJson do
diff --git a/spec/models/blob_viewer/gemspec_spec.rb b/spec/models/blob_viewer/gemspec_spec.rb
index d8c4490637f..b6cc82c03ba 100644
--- a/spec/models/blob_viewer/gemspec_spec.rb
+++ b/spec/models/blob_viewer/gemspec_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::Gemspec do
diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
index 16bf947b493..db405ceb4f1 100644
--- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
+++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::GitlabCiYml do
diff --git a/spec/models/blob_viewer/license_spec.rb b/spec/models/blob_viewer/license_spec.rb
index 222ed166ee0..e02bfae3829 100644
--- a/spec/models/blob_viewer/license_spec.rb
+++ b/spec/models/blob_viewer/license_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::License do
diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb
index fbaa8d47a71..b317278f3c8 100644
--- a/spec/models/blob_viewer/package_json_spec.rb
+++ b/spec/models/blob_viewer/package_json_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::PackageJson do
diff --git a/spec/models/blob_viewer/podspec_json_spec.rb b/spec/models/blob_viewer/podspec_json_spec.rb
index 9a23877b23f..7f1fb8666fd 100644
--- a/spec/models/blob_viewer/podspec_json_spec.rb
+++ b/spec/models/blob_viewer/podspec_json_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::PodspecJson do
diff --git a/spec/models/blob_viewer/podspec_spec.rb b/spec/models/blob_viewer/podspec_spec.rb
index 02d06ea24d6..527ae79d766 100644
--- a/spec/models/blob_viewer/podspec_spec.rb
+++ b/spec/models/blob_viewer/podspec_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::Podspec do
diff --git a/spec/models/blob_viewer/readme_spec.rb b/spec/models/blob_viewer/readme_spec.rb
index 8d11d58cfca..958927bddb4 100644
--- a/spec/models/blob_viewer/readme_spec.rb
+++ b/spec/models/blob_viewer/readme_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::Readme do
diff --git a/spec/models/blob_viewer/route_map_spec.rb b/spec/models/blob_viewer/route_map_spec.rb
index c13662427b0..f7ce873c9d1 100644
--- a/spec/models/blob_viewer/route_map_spec.rb
+++ b/spec/models/blob_viewer/route_map_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::RouteMap do
diff --git a/spec/models/blob_viewer/server_side_spec.rb b/spec/models/blob_viewer/server_side_spec.rb
index 63790486200..f95305abe78 100644
--- a/spec/models/blob_viewer/server_side_spec.rb
+++ b/spec/models/blob_viewer/server_side_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BlobViewer::ServerSide do
diff --git a/spec/models/board_spec.rb b/spec/models/board_spec.rb
index 12d29540137..54452faa0e1 100644
--- a/spec/models/board_spec.rb
+++ b/spec/models/board_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Board do
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 30ca07d5d2c..3ab013ddc0e 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BroadcastMessage do
diff --git a/spec/models/chat_name_spec.rb b/spec/models/chat_name_spec.rb
index 504bc710b25..82991937644 100644
--- a/spec/models/chat_name_spec.rb
+++ b/spec/models/chat_name_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatName do
diff --git a/spec/models/chat_team_spec.rb b/spec/models/chat_team_spec.rb
index 70a9a206faa..76beb3d506b 100644
--- a/spec/models/chat_team_spec.rb
+++ b/spec/models/chat_team_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatTeam do
diff --git a/spec/models/ci/artifact_blob_spec.rb b/spec/models/ci/artifact_blob_spec.rb
index 0014bbcf9f5..f63816fd92a 100644
--- a/spec/models/ci/artifact_blob_spec.rb
+++ b/spec/models/ci/artifact_blob_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::ArtifactBlob do
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index b5ec8991720..aacfbe3f180 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Bridge do
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index 016a5899eef..917a65ddf21 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildMetadata do
diff --git a/spec/models/ci/build_runner_session_spec.rb b/spec/models/ci/build_runner_session_spec.rb
index 35622366829..a52c10019e6 100644
--- a/spec/models/ci/build_runner_session_spec.rb
+++ b/spec/models/ci/build_runner_session_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildRunnerSession, model: true do
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 7500e6ae5b1..2c41dfa65cd 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Build do
@@ -24,6 +26,8 @@ describe Ci::Build do
it { is_expected.to respond_to(:has_trace?) }
it { is_expected.to respond_to(:trace) }
it { is_expected.to delegate_method(:merge_request_event?).to(:pipeline) }
+ it { is_expected.to delegate_method(:merge_request_ref?).to(:pipeline) }
+ it { is_expected.to delegate_method(:legacy_detached_merge_request_pipeline?).to(:pipeline) }
it { is_expected.to be_a(ArtifactMigratable) }
@@ -3626,6 +3630,24 @@ describe Ci::Build do
it { is_expected.to be_falsey }
end
end
+
+ context 'when refspecs feature is required by build' do
+ before do
+ allow(build).to receive(:merge_request_ref?) { true }
+ end
+
+ context 'when runner provides given feature' do
+ let(:runner_features) { { refspecs: true } }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when runner does not provide given feature' do
+ let(:runner_features) { {} }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
describe '#deployment_status' do
diff --git a/spec/models/ci/build_trace_chunks/database_spec.rb b/spec/models/ci/build_trace_chunks/database_spec.rb
index d8fc9d57e95..eb94d7dae38 100644
--- a/spec/models/ci/build_trace_chunks/database_spec.rb
+++ b/spec/models/ci/build_trace_chunks/database_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildTraceChunks::Database do
diff --git a/spec/models/ci/build_trace_chunks/fog_spec.rb b/spec/models/ci/build_trace_chunks/fog_spec.rb
index 8f49190af13..b8d78bcd069 100644
--- a/spec/models/ci/build_trace_chunks/fog_spec.rb
+++ b/spec/models/ci/build_trace_chunks/fog_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildTraceChunks::Fog do
diff --git a/spec/models/ci/build_trace_chunks/redis_spec.rb b/spec/models/ci/build_trace_chunks/redis_spec.rb
index 9da1e6a95ee..6cff33d24fa 100644
--- a/spec/models/ci/build_trace_chunks/redis_spec.rb
+++ b/spec/models/ci/build_trace_chunks/redis_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildTraceChunks::Redis, :clean_gitlab_redis_shared_state do
diff --git a/spec/models/ci/build_trace_section_name_spec.rb b/spec/models/ci/build_trace_section_name_spec.rb
index 386ee6880cb..11e2d27ff79 100644
--- a/spec/models/ci/build_trace_section_name_spec.rb
+++ b/spec/models/ci/build_trace_section_name_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildTraceSectionName, model: true do
diff --git a/spec/models/ci/build_trace_section_spec.rb b/spec/models/ci/build_trace_section_spec.rb
index 541a9a36fb8..5bd3a953ec0 100644
--- a/spec/models/ci/build_trace_section_spec.rb
+++ b/spec/models/ci/build_trace_section_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildTraceSection, model: true do
diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb
index 838fa63cb1f..36c65d92840 100644
--- a/spec/models/ci/group_spec.rb
+++ b/spec/models/ci/group_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Group do
diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb
index 21d96bf3454..b3999765e5f 100644
--- a/spec/models/ci/group_variable_spec.rb
+++ b/spec/models/ci/group_variable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::GroupVariable do
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index c68ba02b8de..d7abd54eec1 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::JobArtifact do
diff --git a/spec/models/ci/legacy_stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb
index 0c33c1466b7..be0307518eb 100644
--- a/spec/models/ci/legacy_stage_spec.rb
+++ b/spec/models/ci/legacy_stage_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::LegacyStage do
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb
index 8ee15f0e734..81913f4a3b6 100644
--- a/spec/models/ci/pipeline_schedule_spec.rb
+++ b/spec/models/ci/pipeline_schedule_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::PipelineSchedule do
diff --git a/spec/models/ci/pipeline_schedule_variable_spec.rb b/spec/models/ci/pipeline_schedule_variable_spec.rb
index dc8427f28bc..3c9379ecb0d 100644
--- a/spec/models/ci/pipeline_schedule_variable_spec.rb
+++ b/spec/models/ci/pipeline_schedule_variable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::PipelineScheduleVariable do
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 5b8097621e0..e76cf376ed1 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Pipeline, :mailer do
@@ -362,6 +364,42 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#merge_request_ref?' do
+ subject { pipeline.merge_request_ref? }
+
+ it 'calls MergeRequest#merge_request_ref?' do
+ expect(MergeRequest).to receive(:merge_request_ref?).with(pipeline.ref)
+
+ subject
+ end
+ end
+
+ describe '#legacy_detached_merge_request_pipeline?' do
+ subject { pipeline.legacy_detached_merge_request_pipeline? }
+
+ set(:merge_request) { create(:merge_request) }
+ let(:ref) { 'feature' }
+ let(:target_sha) { nil }
+
+ let(:pipeline) do
+ build(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: ref, target_sha: target_sha)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when pipeline ref is a merge request ref' do
+ let(:ref) { 'refs/merge-requests/1/head' }
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'when target sha is set' do
+ let(:target_sha) { 'target-sha' }
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
describe '#matches_sha_or_source_sha?' do
subject { pipeline.matches_sha_or_source_sha?(sample_sha) }
@@ -1460,6 +1498,14 @@ describe Ci::Pipeline, :mailer do
end
end
+ context 'with a branch name as the ref' do
+ it 'looks up commit with the full ref name' do
+ expect(pipeline.project).to receive(:commit).with('refs/heads/master').and_call_original
+
+ expect(pipeline).to be_latest
+ end
+ end
+
context 'with not latest sha' do
before do
pipeline.update(
diff --git a/spec/models/ci/pipeline_variable_spec.rb b/spec/models/ci/pipeline_variable_spec.rb
index 03d09cb31d6..2ecb688299a 100644
--- a/spec/models/ci/pipeline_variable_spec.rb
+++ b/spec/models/ci/pipeline_variable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::PipelineVariable do
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index eb2daed7f32..b3ab63925dd 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Runner do
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index 3228c400155..661958390e2 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Stage, :models do
diff --git a/spec/models/ci/trigger_request_spec.rb b/spec/models/ci/trigger_request_spec.rb
index 7dcf3528f73..d04349bec92 100644
--- a/spec/models/ci/trigger_request_spec.rb
+++ b/spec/models/ci/trigger_request_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::TriggerRequest do
diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb
index d4b72205203..fde8375f2a5 100644
--- a/spec/models/ci/trigger_spec.rb
+++ b/spec/models/ci/trigger_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Trigger do
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index 02c07a2bd83..d2df6b3344e 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::Variable do
diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb
index cf5cbf8ec5c..af7eadfc74c 100644
--- a/spec/models/clusters/applications/cert_manager_spec.rb
+++ b/spec/models/clusters/applications/cert_manager_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Clusters::Applications::CertManager do
@@ -9,7 +11,27 @@ describe Clusters::Applications::CertManager do
include_examples 'cluster application initial status specs'
describe '#install_command' do
- let(:cluster_issuer_file) { { "cluster_issuer.yaml": "---\napiVersion: certmanager.k8s.io/v1alpha1\nkind: ClusterIssuer\nmetadata:\n name: letsencrypt-prod\nspec:\n acme:\n server: https://acme-v02.api.letsencrypt.org/directory\n email: admin@example.com\n privateKeySecretRef:\n name: letsencrypt-prod\n http01: {}\n" } }
+ let(:cert_email) { 'admin@example.com' }
+
+ let(:cluster_issuer_file) do
+ file_contents = <<~EOF
+ ---
+ apiVersion: certmanager.k8s.io/v1alpha1
+ kind: ClusterIssuer
+ metadata:
+ name: letsencrypt-prod
+ spec:
+ acme:
+ server: https://acme-v02.api.letsencrypt.org/directory
+ email: #{cert_email}
+ privateKeySecretRef:
+ name: letsencrypt-prod
+ http01: {}
+ EOF
+
+ { "cluster_issuer.yaml": file_contents }
+ end
+
subject { cert_manager.install_command }
it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) }
@@ -24,9 +46,10 @@ describe Clusters::Applications::CertManager do
end
context 'for a specific user' do
+ let(:cert_email) { 'abc@xyz.com' }
+
before do
- cert_manager.email = 'abc@xyz.com'
- cluster_issuer_file[:'cluster_issuer.yaml'].gsub! 'admin@example.com', 'abc@xyz.com'
+ cert_manager.email = cert_email
end
it 'should use his/her email to register issuer with certificate provider' do
diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb
index f16eff92167..f97d126d918 100644
--- a/spec/models/clusters/applications/helm_spec.rb
+++ b/spec/models/clusters/applications/helm_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Clusters::Applications::Helm do
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index a40fa988287..09e60b9a206 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Clusters::Applications::Ingress do
diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb
index 2967c4076c6..5970a1959b5 100644
--- a/spec/models/clusters/applications/jupyter_spec.rb
+++ b/spec/models/clusters/applications/jupyter_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Clusters::Applications::Jupyter do
diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb
index 054ed0be240..25493689fbc 100644
--- a/spec/models/clusters/applications/knative_spec.rb
+++ b/spec/models/clusters/applications/knative_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Clusters::Applications::Knative do
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index 81708b0c2ed..82a502addd4 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Clusters::Applications::Prometheus do
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index 3ce8aa1c7bc..7e2f5835279 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Clusters::Applications::Runner do
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index acbcdc7d170..fabd2806d9a 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -620,4 +620,20 @@ describe Clusters::Cluster do
end
end
end
+
+ describe '#provided_by_user?' do
+ subject { cluster.provided_by_user? }
+
+ context 'with a GCP provider' do
+ let(:cluster) { create(:cluster, :provided_by_gcp) }
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'with an user provider' do
+ let(:cluster) { create(:cluster, :provided_by_user) }
+
+ it { is_expected.to be_truthy }
+ end
+ end
end
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index af65530e663..14bec17a2bd 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching do
@@ -15,7 +17,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it { is_expected.to delegate_method(:project).to(:cluster) }
it { is_expected.to delegate_method(:enabled?).to(:cluster) }
- it { is_expected.to delegate_method(:managed?).to(:cluster) }
+ it { is_expected.to delegate_method(:provided_by_user?).to(:cluster) }
it { is_expected.to delegate_method(:kubernetes_namespace).to(:cluster) }
it_behaves_like 'having unique enum values'
diff --git a/spec/models/clusters/project_spec.rb b/spec/models/clusters/project_spec.rb
index 82ef5a23c18..2f017e69251 100644
--- a/spec/models/clusters/project_spec.rb
+++ b/spec/models/clusters/project_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Clusters::Project do
diff --git a/spec/models/clusters/providers/gcp_spec.rb b/spec/models/clusters/providers/gcp_spec.rb
index 5012e6f15c6..785db4febe0 100644
--- a/spec/models/clusters/providers/gcp_spec.rb
+++ b/spec/models/clusters/providers/gcp_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Clusters::Providers::Gcp do
diff --git a/spec/models/commit_collection_spec.rb b/spec/models/commit_collection_spec.rb
index 30c504ebea8..8a7fcb39fe2 100644
--- a/spec/models/commit_collection_spec.rb
+++ b/spec/models/commit_collection_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CommitCollection do
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index f2efcd9d0e9..b96ca89c893 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CommitRange do
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 9d4e18534ae..14f4b4d692f 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Commit do
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index e2b7f5c6ee2..ca2f9e36c98 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CommitStatus do
diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb
index 0bc3ee014e6..43c3580bed2 100644
--- a/spec/models/compare_spec.rb
+++ b/spec/models/compare_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Compare do
diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb
index 04d6cfa2c02..de2bc3a387b 100644
--- a/spec/models/concerns/access_requestable_spec.rb
+++ b/spec/models/concerns/access_requestable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe AccessRequestable do
diff --git a/spec/models/concerns/avatarable_spec.rb b/spec/models/concerns/avatarable_spec.rb
index 1ea7f2b9985..c750be6b75c 100644
--- a/spec/models/concerns/avatarable_spec.rb
+++ b/spec/models/concerns/avatarable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Avatarable do
diff --git a/spec/models/concerns/awardable_spec.rb b/spec/models/concerns/awardable_spec.rb
index 5713106418d..9e7106281ee 100644
--- a/spec/models/concerns/awardable_spec.rb
+++ b/spec/models/concerns/awardable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Awardable do
diff --git a/spec/models/concerns/batch_destroy_dependent_associations_spec.rb b/spec/models/concerns/batch_destroy_dependent_associations_spec.rb
index e5392fe0462..1fe90d3cc9a 100644
--- a/spec/models/concerns/batch_destroy_dependent_associations_spec.rb
+++ b/spec/models/concerns/batch_destroy_dependent_associations_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BatchDestroyDependentAssociations do
diff --git a/spec/models/concerns/blocks_json_serialization_spec.rb b/spec/models/concerns/blocks_json_serialization_spec.rb
index 5906b588d0e..e8657c45a93 100644
--- a/spec/models/concerns/blocks_json_serialization_spec.rb
+++ b/spec/models/concerns/blocks_json_serialization_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe BlocksJsonSerialization do
diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb
index 7d555f15e39..78637ff10c6 100644
--- a/spec/models/concerns/cache_markdown_field_spec.rb
+++ b/spec/models/concerns/cache_markdown_field_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CacheMarkdownField do
diff --git a/spec/models/concerns/cacheable_attributes_spec.rb b/spec/models/concerns/cacheable_attributes_spec.rb
index 43a544cfe26..394fac52aa7 100644
--- a/spec/models/concerns/cacheable_attributes_spec.rb
+++ b/spec/models/concerns/cacheable_attributes_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CacheableAttributes do
diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb
index 1bf6c9b3404..d6d41a25eac 100644
--- a/spec/models/concerns/case_sensitivity_spec.rb
+++ b/spec/models/concerns/case_sensitivity_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CaseSensitivity do
diff --git a/spec/models/concerns/chronic_duration_attribute_spec.rb b/spec/models/concerns/chronic_duration_attribute_spec.rb
index 51221e07ca3..e41d75568f7 100644
--- a/spec/models/concerns/chronic_duration_attribute_spec.rb
+++ b/spec/models/concerns/chronic_duration_attribute_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples 'ChronicDurationAttribute reader' do
diff --git a/spec/models/concerns/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb
index 6951be903fe..42bed9434f5 100644
--- a/spec/models/concerns/deployable_spec.rb
+++ b/spec/models/concerns/deployable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Deployable do
diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb
index 19ab4382b53..0e34d8fccf3 100644
--- a/spec/models/concerns/deployment_platform_spec.rb
+++ b/spec/models/concerns/deployment_platform_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe DeploymentPlatform do
diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb
index 64bf04071e8..baddca47dfa 100644
--- a/spec/models/concerns/discussion_on_diff_spec.rb
+++ b/spec/models/concerns/discussion_on_diff_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DiscussionOnDiff do
diff --git a/spec/models/concerns/each_batch_spec.rb b/spec/models/concerns/each_batch_spec.rb
index 17224c09693..c4cf8e80f7a 100644
--- a/spec/models/concerns/each_batch_spec.rb
+++ b/spec/models/concerns/each_batch_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe EachBatch do
diff --git a/spec/models/concerns/editable_spec.rb b/spec/models/concerns/editable_spec.rb
index 49a9a8ebcbc..4a4a3ca5687 100644
--- a/spec/models/concerns/editable_spec.rb
+++ b/spec/models/concerns/editable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Editable do
diff --git a/spec/models/concerns/expirable_spec.rb b/spec/models/concerns/expirable_spec.rb
index f7b436f32e6..f4f5eab5b86 100644
--- a/spec/models/concerns/expirable_spec.rb
+++ b/spec/models/concerns/expirable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Expirable do
diff --git a/spec/models/concerns/faster_cache_keys_spec.rb b/spec/models/concerns/faster_cache_keys_spec.rb
index 8d3f94267fa..7830acbae3d 100644
--- a/spec/models/concerns/faster_cache_keys_spec.rb
+++ b/spec/models/concerns/faster_cache_keys_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe FasterCacheKeys do
diff --git a/spec/models/concerns/feature_gate_spec.rb b/spec/models/concerns/feature_gate_spec.rb
index 3f601243245..276d3d9e1d5 100644
--- a/spec/models/concerns/feature_gate_spec.rb
+++ b/spec/models/concerns/feature_gate_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe FeatureGate do
diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb
index 28352d8c961..194caac3fce 100644
--- a/spec/models/concerns/group_descendant_spec.rb
+++ b/spec/models/concerns/group_descendant_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupDescendant, :nested_groups do
diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb
index e8b1eba67cc..a217dc42537 100644
--- a/spec/models/concerns/has_status_spec.rb
+++ b/spec/models/concerns/has_status_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe HasStatus do
diff --git a/spec/models/concerns/has_variable_spec.rb b/spec/models/concerns/has_variable_spec.rb
index bff96e12ffa..2bb21d7934e 100644
--- a/spec/models/concerns/has_variable_spec.rb
+++ b/spec/models/concerns/has_variable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe HasVariable do
diff --git a/spec/models/concerns/ignorable_column_spec.rb b/spec/models/concerns/ignorable_column_spec.rb
index b70f2331a0e..6b82825d2cc 100644
--- a/spec/models/concerns/ignorable_column_spec.rb
+++ b/spec/models/concerns/ignorable_column_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe IgnorableColumn do
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 72c6161424b..259ac6852a8 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Issuable do
diff --git a/spec/models/concerns/loaded_in_group_list_spec.rb b/spec/models/concerns/loaded_in_group_list_spec.rb
index 7a279547a3a..7c97b580779 100644
--- a/spec/models/concerns/loaded_in_group_list_spec.rb
+++ b/spec/models/concerns/loaded_in_group_list_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe LoadedInGroupList do
diff --git a/spec/models/concerns/manual_inverse_association_spec.rb b/spec/models/concerns/manual_inverse_association_spec.rb
index ff4a04ea573..ee32e3b165b 100644
--- a/spec/models/concerns/manual_inverse_association_spec.rb
+++ b/spec/models/concerns/manual_inverse_association_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ManualInverseAssociation do
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index a9b237fa9ea..f31e3e8821d 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Mentionable do
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
index 81ca5b638fe..22d4b2cc517 100644
--- a/spec/models/concerns/milestoneish_spec.rb
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Milestone, 'Milestoneish' do
diff --git a/spec/models/concerns/noteable_spec.rb b/spec/models/concerns/noteable_spec.rb
index 485a6e165a1..ee613b199ad 100644
--- a/spec/models/concerns/noteable_spec.rb
+++ b/spec/models/concerns/noteable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Noteable do
diff --git a/spec/models/concerns/participable_spec.rb b/spec/models/concerns/participable_spec.rb
index 431f1482615..3d5937c4fc6 100644
--- a/spec/models/concerns/participable_spec.rb
+++ b/spec/models/concerns/participable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Participable do
diff --git a/spec/models/concerns/presentable_spec.rb b/spec/models/concerns/presentable_spec.rb
index 941647a79fb..9db868dd348 100644
--- a/spec/models/concerns/presentable_spec.rb
+++ b/spec/models/concerns/presentable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Presentable do
diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb
index 9041690023f..5aa43b58217 100644
--- a/spec/models/concerns/project_features_compatibility_spec.rb
+++ b/spec/models/concerns/project_features_compatibility_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectFeaturesCompatibility do
diff --git a/spec/models/concerns/prometheus_adapter_spec.rb b/spec/models/concerns/prometheus_adapter_spec.rb
index f4b9c57e71a..7148261b1e4 100644
--- a/spec/models/concerns/prometheus_adapter_spec.rb
+++ b/spec/models/concerns/prometheus_adapter_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PrometheusAdapter, :use_clean_rails_memory_store_caching do
diff --git a/spec/models/concerns/protected_ref_access_spec.rb b/spec/models/concerns/protected_ref_access_spec.rb
index ce602337647..94798f0590d 100644
--- a/spec/models/concerns/protected_ref_access_spec.rb
+++ b/spec/models/concerns/protected_ref_access_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProtectedRefAccess do
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index 03ae45e6b17..32e13d5abed 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ReactiveCaching, :use_clean_rails_memory_store_caching do
diff --git a/spec/models/concerns/redactable_spec.rb b/spec/models/concerns/redactable_spec.rb
index 7feeaa54069..57c7d2cb767 100644
--- a/spec/models/concerns/redactable_spec.rb
+++ b/spec/models/concerns/redactable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Redactable do
diff --git a/spec/models/concerns/redis_cacheable_spec.rb b/spec/models/concerns/redis_cacheable_spec.rb
index 23c6c6233e9..a9dca27f258 100644
--- a/spec/models/concerns/redis_cacheable_spec.rb
+++ b/spec/models/concerns/redis_cacheable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RedisCacheable do
diff --git a/spec/models/concerns/relative_positioning_spec.rb b/spec/models/concerns/relative_positioning_spec.rb
index ac8da30b6c9..d0ae45f7871 100644
--- a/spec/models/concerns/relative_positioning_spec.rb
+++ b/spec/models/concerns/relative_positioning_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RelativePositioning do
diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb
index 97b046b0f21..9ea01ca9002 100644
--- a/spec/models/concerns/resolvable_discussion_spec.rb
+++ b/spec/models/concerns/resolvable_discussion_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Discussion, ResolvableDiscussion do
diff --git a/spec/models/concerns/resolvable_note_spec.rb b/spec/models/concerns/resolvable_note_spec.rb
index fcb5250278e..4f46252a044 100644
--- a/spec/models/concerns/resolvable_note_spec.rb
+++ b/spec/models/concerns/resolvable_note_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Note, ResolvableNote do
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index 565266321d3..1fb0dd5030c 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Group, 'Routable' do
diff --git a/spec/models/concerns/sha_attribute_spec.rb b/spec/models/concerns/sha_attribute_spec.rb
index 0d3beb6a6e3..a4a81ae126d 100644
--- a/spec/models/concerns/sha_attribute_spec.rb
+++ b/spec/models/concerns/sha_attribute_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ShaAttribute do
diff --git a/spec/models/concerns/sortable_spec.rb b/spec/models/concerns/sortable_spec.rb
index 0a9d2021a19..184f7986a6f 100644
--- a/spec/models/concerns/sortable_spec.rb
+++ b/spec/models/concerns/sortable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Sortable do
diff --git a/spec/models/concerns/spammable_spec.rb b/spec/models/concerns/spammable_spec.rb
index e698207166c..650d49e41a1 100644
--- a/spec/models/concerns/spammable_spec.rb
+++ b/spec/models/concerns/spammable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Spammable do
diff --git a/spec/models/concerns/strip_attribute_spec.rb b/spec/models/concerns/strip_attribute_spec.rb
index 8c945686b66..5c0d1042e06 100644
--- a/spec/models/concerns/strip_attribute_spec.rb
+++ b/spec/models/concerns/strip_attribute_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe StripAttribute do
diff --git a/spec/models/concerns/subscribable_spec.rb b/spec/models/concerns/subscribable_spec.rb
index 45dfb136aea..2f88adf08dd 100644
--- a/spec/models/concerns/subscribable_spec.rb
+++ b/spec/models/concerns/subscribable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Subscribable, 'Subscribable' do
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index 40cb4eef60a..51e28974ae0 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples 'TokenAuthenticatable' do
diff --git a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb
index 2a0182b4294..7332da309d5 100644
--- a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb
+++ b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TokenAuthenticatableStrategies::Base do
diff --git a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
index ca38f86c5ab..70f41981b3b 100644
--- a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
+++ b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TokenAuthenticatableStrategies::Encrypted do
diff --git a/spec/models/concerns/triggerable_hooks_spec.rb b/spec/models/concerns/triggerable_hooks_spec.rb
index 265abd6bd72..f28e5f56411 100644
--- a/spec/models/concerns/triggerable_hooks_spec.rb
+++ b/spec/models/concerns/triggerable_hooks_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
RSpec.describe TriggerableHooks do
diff --git a/spec/models/concerns/uniquify_spec.rb b/spec/models/concerns/uniquify_spec.rb
index 6cd2de6dcce..9ba35702ba6 100644
--- a/spec/models/concerns/uniquify_spec.rb
+++ b/spec/models/concerns/uniquify_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Uniquify do
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index e46945e301e..013112d1d51 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ContainerRepository do
diff --git a/spec/models/conversational_development_index/metric_spec.rb b/spec/models/conversational_development_index/metric_spec.rb
index b3193619503..60b1a860dfd 100644
--- a/spec/models/conversational_development_index/metric_spec.rb
+++ b/spec/models/conversational_development_index/metric_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe ConversationalDevelopmentIndex::Metric do
diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb
index 6a6b58fb52b..b22a0340015 100644
--- a/spec/models/cycle_analytics/code_spec.rb
+++ b/spec/models/cycle_analytics/code_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'CycleAnalytics#code' do
diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb
index 45f1b4fe8a3..07d60be091a 100644
--- a/spec/models/cycle_analytics/issue_spec.rb
+++ b/spec/models/cycle_analytics/issue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'CycleAnalytics#issue' do
diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb
index d366e2b723a..3d22a284264 100644
--- a/spec/models/cycle_analytics/plan_spec.rb
+++ b/spec/models/cycle_analytics/plan_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'CycleAnalytics#plan' do
diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb
index 156eb96cfce..383727cd8f7 100644
--- a/spec/models/cycle_analytics/production_spec.rb
+++ b/spec/models/cycle_analytics/production_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'CycleAnalytics#production' do
diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb
index 0aedfb49cb5..1af5f9cc1f4 100644
--- a/spec/models/cycle_analytics/review_spec.rb
+++ b/spec/models/cycle_analytics/review_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'CycleAnalytics#review' do
diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb
index 0cbda50c688..8375944f03c 100644
--- a/spec/models/cycle_analytics/staging_spec.rb
+++ b/spec/models/cycle_analytics/staging_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'CycleAnalytics#staging' do
diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb
index e58b8fdff58..b78258df564 100644
--- a/spec/models/cycle_analytics/test_spec.rb
+++ b/spec/models/cycle_analytics/test_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'CycleAnalytics#test' do
diff --git a/spec/models/cycle_analytics_spec.rb b/spec/models/cycle_analytics_spec.rb
index 0fe24870f02..5d8b5b573cf 100644
--- a/spec/models/cycle_analytics_spec.rb
+++ b/spec/models/cycle_analytics_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CycleAnalytics do
diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb
index 41440c6d288..ec6cfb6b826 100644
--- a/spec/models/deploy_key_spec.rb
+++ b/spec/models/deploy_key_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DeployKey, :mailer do
diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb
index fca3090ff4a..c137444763b 100644
--- a/spec/models/deploy_keys_project_spec.rb
+++ b/spec/models/deploy_keys_project_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DeployKeysProject do
diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb
index 3435f93c999..05320703e25 100644
--- a/spec/models/deploy_token_spec.rb
+++ b/spec/models/deploy_token_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DeployToken do
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 5fce9504334..d9170d5fa07 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Deployment do
diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb
index 50b19000799..cfeb4382927 100644
--- a/spec/models/diff_discussion_spec.rb
+++ b/spec/models/diff_discussion_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DiffDiscussion do
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 67e5f4f7e41..fa19cb47a0d 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DiffNote do
diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb
index f4efe5a7b3a..b8bdeb781dc 100644
--- a/spec/models/diff_viewer/base_spec.rb
+++ b/spec/models/diff_viewer/base_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DiffViewer::Base do
diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb
index 86b14b6ebf3..27de0584b8a 100644
--- a/spec/models/diff_viewer/server_side_spec.rb
+++ b/spec/models/diff_viewer/server_side_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DiffViewer::ServerSide do
diff --git a/spec/models/discussion_spec.rb b/spec/models/discussion_spec.rb
index a46f7ed6507..0d02165787a 100644
--- a/spec/models/discussion_spec.rb
+++ b/spec/models/discussion_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Discussion do
diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb
index 47eb0717c0c..cae88f39660 100644
--- a/spec/models/email_spec.rb
+++ b/spec/models/email_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Email do
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index ab1b306e597..448ed35cb1e 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Environment do
diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb
index 2576a9aba06..c503c35305f 100644
--- a/spec/models/environment_status_spec.rb
+++ b/spec/models/environment_status_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe EnvironmentStatus do
diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
index cbde13a2c7a..21e381d9fb7 100644
--- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb
+++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
@@ -167,7 +167,7 @@ describe ErrorTracking::ProjectErrorTrackingSetting do
end
end
- context 'when sentry client raises exception' do
+ context 'when sentry client raises Sentry::Client::Error' do
let(:sentry_client) { spy(:sentry_client) }
before do
@@ -179,7 +179,31 @@ describe ErrorTracking::ProjectErrorTrackingSetting do
end
it 'returns error' do
- expect(result).to eq(error: 'error message')
+ expect(result).to eq(
+ error: 'error message',
+ error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_NON_20X_RESPONSE
+ )
+ expect(subject).to have_received(:sentry_client)
+ expect(sentry_client).to have_received(:list_issues)
+ end
+ end
+
+ context 'when sentry client raises Sentry::Client::MissingKeysError' do
+ let(:sentry_client) { spy(:sentry_client) }
+
+ before do
+ synchronous_reactive_cache(subject)
+
+ allow(subject).to receive(:sentry_client).and_return(sentry_client)
+ allow(sentry_client).to receive(:list_issues).with(opts)
+ .and_raise(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"')
+ end
+
+ it 'returns error' do
+ expect(result).to eq(
+ error: 'Sentry API response is missing keys. key not found: "id"',
+ error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_MISSING_KEYS
+ )
expect(subject).to have_received(:sentry_client)
expect(sentry_client).to have_received(:list_issues)
end
diff --git a/spec/models/event_collection_spec.rb b/spec/models/event_collection_spec.rb
index 6078f429bdc..efe511042c3 100644
--- a/spec/models/event_collection_spec.rb
+++ b/spec/models/event_collection_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe EventCollection do
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index ce4f8ee4705..d192fe70506 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Event do
diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb
index 83ba22caa03..9d064d458f0 100644
--- a/spec/models/external_issue_spec.rb
+++ b/spec/models/external_issue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ExternalIssue do
diff --git a/spec/models/fork_network_member_spec.rb b/spec/models/fork_network_member_spec.rb
index 60d04562e6c..eab758248de 100644
--- a/spec/models/fork_network_member_spec.rb
+++ b/spec/models/fork_network_member_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ForkNetworkMember do
diff --git a/spec/models/fork_network_spec.rb b/spec/models/fork_network_spec.rb
index a43baf1820a..5ec0f8d6b02 100644
--- a/spec/models/fork_network_spec.rb
+++ b/spec/models/fork_network_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ForkNetwork do
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index a3e68d2e646..c851810ffb3 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GenericCommitStatus do
diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb
index f93904065c7..9d901d01a52 100644
--- a/spec/models/global_milestone_spec.rb
+++ b/spec/models/global_milestone_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GlobalMilestone do
diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb
index 58a1d2e4ea2..479b39cd139 100644
--- a/spec/models/gpg_key_spec.rb
+++ b/spec/models/gpg_key_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe GpgKey do
diff --git a/spec/models/gpg_key_subkey_spec.rb b/spec/models/gpg_key_subkey_spec.rb
index 3c86837f47f..51d2f9cb9ac 100644
--- a/spec/models/gpg_key_subkey_spec.rb
+++ b/spec/models/gpg_key_subkey_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe GpgKeySubkey do
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb
index e90319c39b1..47c343edf0e 100644
--- a/spec/models/gpg_signature_spec.rb
+++ b/spec/models/gpg_signature_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
RSpec.describe GpgSignature do
diff --git a/spec/models/group_custom_attribute_spec.rb b/spec/models/group_custom_attribute_spec.rb
index 7ecb2022567..7d60c74b62b 100644
--- a/spec/models/group_custom_attribute_spec.rb
+++ b/spec/models/group_custom_attribute_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupCustomAttribute do
diff --git a/spec/models/group_label_spec.rb b/spec/models/group_label_spec.rb
index d0fc1eaa3ec..a3a5c631c3d 100644
--- a/spec/models/group_label_spec.rb
+++ b/spec/models/group_label_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupLabel do
diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb
index fcc33cd95fe..01856870fe0 100644
--- a/spec/models/group_milestone_spec.rb
+++ b/spec/models/group_milestone_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupMilestone do
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 16624ce47d0..2c6abddca17 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Group do
diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb
index fc30f3056e5..93862e98172 100644
--- a/spec/models/guest_spec.rb
+++ b/spec/models/guest_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Guest do
diff --git a/spec/models/hooks/active_hook_filter_spec.rb b/spec/models/hooks/active_hook_filter_spec.rb
index df7edda2213..1249c793f7f 100644
--- a/spec/models/hooks/active_hook_filter_spec.rb
+++ b/spec/models/hooks/active_hook_filter_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ActiveHookFilter do
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index 5dd31b1b5de..a945f0d1516 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectHook do
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index e32eaafc13f..936c2fbad27 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ServiceHook do
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index edd1cb455af..e0d4d2e4858 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe SystemHook do
diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb
index 744a6ccae8b..f812149c9be 100644
--- a/spec/models/hooks/web_hook_log_spec.rb
+++ b/spec/models/hooks/web_hook_log_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe WebHookLog do
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index a308ac6e33a..fe08dc4f5e6 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe WebHook do
diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb
index e1a7a59dfd1..74ddc2d6284 100644
--- a/spec/models/identity_spec.rb
+++ b/spec/models/identity_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Identity do
diff --git a/spec/models/import_export_upload_spec.rb b/spec/models/import_export_upload_spec.rb
index 58af84b8a08..18a714f4d98 100644
--- a/spec/models/import_export_upload_spec.rb
+++ b/spec/models/import_export_upload_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ImportExportUpload do
diff --git a/spec/models/instance_configuration_spec.rb b/spec/models/instance_configuration_spec.rb
index cb3d6c7cda2..e65f97df3c3 100644
--- a/spec/models/instance_configuration_spec.rb
+++ b/spec/models/instance_configuration_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe InstanceConfiguration do
@@ -30,8 +32,8 @@ describe InstanceConfiguration do
end
def stub_pub_file(exist: true)
- path = 'spec/fixtures/ssh_host_example_key.pub'
- path << 'random' unless exist
+ path = exist ? 'spec/fixtures/ssh_host_example_key.pub' : 'spec/fixtures/ssh_host_example_key.pub.random'
+
allow(subject).to receive(:ssh_algorithm_file).and_return(Rails.root.join(path))
end
end
diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb
index d32f163f05b..ff2382838ae 100644
--- a/spec/models/internal_id_spec.rb
+++ b/spec/models/internal_id_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe InternalId do
diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb
index b7291eebe64..07858fe8a70 100644
--- a/spec/models/issue/metrics_spec.rb
+++ b/spec/models/issue/metrics_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Issue::Metrics do
diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb
index 580a98193af..7fc635f100f 100644
--- a/spec/models/issue_collection_spec.rb
+++ b/spec/models/issue_collection_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe IssueCollection do
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 6101df2e099..892dd053e39 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Issue do
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 06d26ef89f1..a0b6eff88d5 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Key, :mailer do
diff --git a/spec/models/label_link_spec.rb b/spec/models/label_link_spec.rb
index e2b49bc2de7..b160e72e759 100644
--- a/spec/models/label_link_spec.rb
+++ b/spec/models/label_link_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe LabelLink do
diff --git a/spec/models/label_priority_spec.rb b/spec/models/label_priority_spec.rb
index 9dcb0f06b20..1a93468290f 100644
--- a/spec/models/label_priority_spec.rb
+++ b/spec/models/label_priority_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe LabelPriority do
diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb
index 3fc6c06b7fa..5174c590a10 100644
--- a/spec/models/label_spec.rb
+++ b/spec/models/label_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Label do
diff --git a/spec/models/legacy_diff_discussion_spec.rb b/spec/models/legacy_diff_discussion_spec.rb
index dae97b69c84..49ea319fbd1 100644
--- a/spec/models/legacy_diff_discussion_spec.rb
+++ b/spec/models/legacy_diff_discussion_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe LegacyDiffDiscussion do
diff --git a/spec/models/lfs_download_object_spec.rb b/spec/models/lfs_download_object_spec.rb
index 88838b127d2..effd8b08124 100644
--- a/spec/models/lfs_download_object_spec.rb
+++ b/spec/models/lfs_download_object_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe LfsDownloadObject do
diff --git a/spec/models/lfs_file_lock_spec.rb b/spec/models/lfs_file_lock_spec.rb
index 41ca1578b94..aa64d66944b 100644
--- a/spec/models/lfs_file_lock_spec.rb
+++ b/spec/models/lfs_file_lock_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe LfsFileLock do
diff --git a/spec/models/lfs_object_spec.rb b/spec/models/lfs_object_spec.rb
index 3f929710862..3d4d4b7d795 100644
--- a/spec/models/lfs_object_spec.rb
+++ b/spec/models/lfs_object_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe LfsObject do
diff --git a/spec/models/lfs_objects_project_spec.rb b/spec/models/lfs_objects_project_spec.rb
index 0a3180f43e8..3e86ee38566 100644
--- a/spec/models/lfs_objects_project_spec.rb
+++ b/spec/models/lfs_objects_project_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe LfsObjectsProject do
diff --git a/spec/models/license_template_spec.rb b/spec/models/license_template_spec.rb
index dd912eefac1..7037277e580 100644
--- a/spec/models/license_template_spec.rb
+++ b/spec/models/license_template_spec.rb
@@ -1,16 +1,19 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe LicenseTemplate do
describe '#content' do
it 'calls a proc exactly once if provided' do
- lazy = build_template(-> { 'bar' })
- content = lazy.content
+ content_proc = -> { 'bar' }
+ expect(content_proc).to receive(:call).once.and_call_original
+
+ lazy = build_template(content_proc)
- expect(content).to eq('bar')
- expect(content.object_id).to eq(lazy.content.object_id)
+ expect(lazy.content).to eq('bar')
- content.replace('foo')
- expect(lazy.content).to eq('foo')
+ # Subsequent calls should not call proc again
+ expect(lazy.content).to eq('bar')
end
it 'returns a string if provided' do
diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb
index a51580f8292..18d4549977c 100644
--- a/spec/models/list_spec.rb
+++ b/spec/models/list_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe List do
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 188beac1582..c68c3ce2abe 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Member do
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index bc937368cff..f227abd3dae 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupMember do
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 36bfff2c339..497764b6825 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectMember do
diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb
index 02ff7839739..49573af0fed 100644
--- a/spec/models/merge_request/metrics_spec.rb
+++ b/spec/models/merge_request/metrics_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MergeRequest::Metrics do
diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb
index 10487190a44..ab2aadf7d88 100644
--- a/spec/models/merge_request_diff_commit_spec.rb
+++ b/spec/models/merge_request_diff_commit_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe MergeRequestDiffCommit do
diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb
index faa47660a74..66957c24fdc 100644
--- a/spec/models/merge_request_diff_file_spec.rb
+++ b/spec/models/merge_request_diff_file_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe MergeRequestDiffFile do
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index 0f00ea7e85e..a53add67066 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MergeRequestDiff do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index a1de0c63623..fb32f72e2de 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MergeRequest do
@@ -2712,14 +2714,21 @@ describe MergeRequest do
end
describe '#has_commits?' do
- before do
+ it 'returns true when merge request diff has commits' do
allow(subject.merge_request_diff).to receive(:commits_count)
.and_return(2)
- end
- it 'returns true when merge request diff has commits' do
expect(subject.has_commits?).to be_truthy
end
+
+ context 'when commits_count is nil' do
+ it 'returns false' do
+ allow(subject.merge_request_diff).to receive(:commits_count)
+ .and_return(nil)
+
+ expect(subject.has_commits?).to be_falsey
+ end
+ end
end
describe '#has_no_commits?' do
@@ -3081,6 +3090,38 @@ describe MergeRequest do
end
end
+ describe '#mergeable_to_ref?' do
+ it 'returns true when merge request is mergeable' do
+ subject = create(:merge_request)
+
+ expect(subject.mergeable_to_ref?).to be(true)
+ end
+
+ it 'returns false when merge request is already merged' do
+ subject = create(:merge_request, :merged)
+
+ expect(subject.mergeable_to_ref?).to be(false)
+ end
+
+ it 'returns false when merge request is closed' do
+ subject = create(:merge_request, :closed)
+
+ expect(subject.mergeable_to_ref?).to be(false)
+ end
+
+ it 'returns false when merge request is work in progress' do
+ subject = create(:merge_request, title: 'WIP: The feature')
+
+ expect(subject.mergeable_to_ref?).to be(false)
+ end
+
+ it 'returns false when merge request has no commits' do
+ subject = create(:merge_request, source_branch: 'empty-branch', target_branch: 'master')
+
+ expect(subject.mergeable_to_ref?).to be(false)
+ end
+ end
+
describe '#merge_participants' do
it 'contains author' do
expect(subject.merge_participants).to eq([subject.author])
@@ -3115,4 +3156,32 @@ describe MergeRequest do
end
end
end
+
+ describe '.merge_request_ref?' do
+ subject { described_class.merge_request_ref?(ref) }
+
+ context 'when ref is ref name of a branch' do
+ let(:ref) { 'feature' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when ref is HEAD ref path of a branch' do
+ let(:ref) { 'refs/heads/feature' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when ref is HEAD ref path of a merge request' do
+ let(:ref) { 'refs/merge-requests/1/head' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when ref is merge ref path of a merge request' do
+ let(:ref) { 'refs/merge-requests/1/merge' }
+
+ it { is_expected.to be_truthy }
+ end
+ end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 717d4ae4ec0..b82368318f2 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Milestone do
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index aadc298ae0b..62e7dd3231b 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Namespace do
diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb
index c364dd6643b..d1a2bedf542 100644
--- a/spec/models/network/graph_spec.rb
+++ b/spec/models/network/graph_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Network::Graph do
diff --git a/spec/models/note_diff_file_spec.rb b/spec/models/note_diff_file_spec.rb
index 591c1a89748..99eeac8d778 100644
--- a/spec/models/note_diff_file_spec.rb
+++ b/spec/models/note_diff_file_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe NoteDiffFile do
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index eb6f6ff5faf..7a1ab20186a 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Note do
diff --git a/spec/models/notification_recipient_spec.rb b/spec/models/notification_recipient_spec.rb
index 13fe47799ed..3710f2be287 100644
--- a/spec/models/notification_recipient_spec.rb
+++ b/spec/models/notification_recipient_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe NotificationRecipient do
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index c8ab564e3bc..85128456918 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
RSpec.describe NotificationSetting do
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index 4b85c5e8720..142ddebbbf8 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PagesDomain do
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index c82ab9c9e62..e0e1101ffc6 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PersonalAccessToken do
diff --git a/spec/models/programming_language_spec.rb b/spec/models/programming_language_spec.rb
index 99cd358f863..b327d360461 100644
--- a/spec/models/programming_language_spec.rb
+++ b/spec/models/programming_language_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProgrammingLanguage do
diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb
index c289ee0859a..6f06fe4e55a 100644
--- a/spec/models/project_authorization_spec.rb
+++ b/spec/models/project_authorization_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectAuthorization do
diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb
index 7ff64c76e37..8ad28ce68cc 100644
--- a/spec/models/project_auto_devops_spec.rb
+++ b/spec/models/project_auto_devops_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectAutoDevops do
diff --git a/spec/models/project_custom_attribute_spec.rb b/spec/models/project_custom_attribute_spec.rb
index 669de5506bc..80638676b49 100644
--- a/spec/models/project_custom_attribute_spec.rb
+++ b/spec/models/project_custom_attribute_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectCustomAttribute do
diff --git a/spec/models/project_deploy_token_spec.rb b/spec/models/project_deploy_token_spec.rb
index 9e2e40c2e8f..2a5fefc1ab0 100644
--- a/spec/models/project_deploy_token_spec.rb
+++ b/spec/models/project_deploy_token_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
RSpec.describe ProjectDeployToken, type: :model do
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
index fee7d65c217..50c9d5968ac 100644
--- a/spec/models/project_feature_spec.rb
+++ b/spec/models/project_feature_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectFeature do
diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb
index 5bea21427d4..dad5506900b 100644
--- a/spec/models/project_group_link_spec.rb
+++ b/spec/models/project_group_link_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectGroupLink do
diff --git a/spec/models/project_import_state_spec.rb b/spec/models/project_import_state_spec.rb
index e3b2d971419..472bf8f9713 100644
--- a/spec/models/project_import_state_spec.rb
+++ b/spec/models/project_import_state_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe ProjectImportState, type: :model do
diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb
index 689d4e505e5..330aab9f856 100644
--- a/spec/models/project_label_spec.rb
+++ b/spec/models/project_label_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectLabel do
diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb
index e66109fd98f..18e839bcc64 100644
--- a/spec/models/project_services/asana_service_spec.rb
+++ b/spec/models/project_services/asana_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe AsanaService do
diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb
index 5cb6d63659e..7742e33e901 100644
--- a/spec/models/project_services/assembla_service_spec.rb
+++ b/spec/models/project_services/assembla_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe AssemblaService do
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index b880d90d28f..08c510f09df 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BambooService, :use_clean_rails_memory_store_caching do
diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb
index 43f7bcb1a19..6818db48fee 100644
--- a/spec/models/project_services/bugzilla_service_spec.rb
+++ b/spec/models/project_services/bugzilla_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BugzillaService do
diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index 1615a93a4ca..091d4d8f695 100644
--- a/spec/models/project_services/buildkite_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BuildkiteService, :use_clean_rails_memory_store_caching do
diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb
index ed8347edffd..bf4c52fc7ab 100644
--- a/spec/models/project_services/campfire_service_spec.rb
+++ b/spec/models/project_services/campfire_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CampfireService do
diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb
index f7a35fdc88a..d3adc62c38e 100644
--- a/spec/models/project_services/chat_message/issue_message_spec.rb
+++ b/spec/models/project_services/chat_message/issue_message_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatMessage::IssueMessage do
diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb
index 7997b5bb6b9..b56eb19dd55 100644
--- a/spec/models/project_services/chat_message/merge_message_spec.rb
+++ b/spec/models/project_services/chat_message/merge_message_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatMessage::MergeMessage do
diff --git a/spec/models/project_services/chat_message/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb
index 5abbd7bec18..5e7987dc0f6 100644
--- a/spec/models/project_services/chat_message/note_message_spec.rb
+++ b/spec/models/project_services/chat_message/note_message_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatMessage::NoteMessage do
diff --git a/spec/models/project_services/chat_message/pipeline_message_spec.rb b/spec/models/project_services/chat_message/pipeline_message_spec.rb
index 0ff20400999..8f9fa310ad4 100644
--- a/spec/models/project_services/chat_message/pipeline_message_spec.rb
+++ b/spec/models/project_services/chat_message/pipeline_message_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatMessage::PipelineMessage do
diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb
index 973d6bdb2a0..a89645a3ea8 100644
--- a/spec/models/project_services/chat_message/push_message_spec.rb
+++ b/spec/models/project_services/chat_message/push_message_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatMessage::PushMessage do
diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
index 7efcba9bcfd..c3db516f253 100644
--- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb
+++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatMessage::WikiPageMessage do
diff --git a/spec/models/project_services/chat_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb
index 46713df77da..6f4ddd223f6 100644
--- a/spec/models/project_services/chat_notification_service_spec.rb
+++ b/spec/models/project_services/chat_notification_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ChatNotificationService do
diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb
index 7e1b1a4f2af..f0e7551693d 100644
--- a/spec/models/project_services/custom_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CustomIssueTrackerService do
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index 26597d9b83c..22df19d943f 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DroneCiService, :use_clean_rails_memory_store_caching do
diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb
index d9b7010e5e5..0a58eb367e3 100644
--- a/spec/models/project_services/emails_on_push_service_spec.rb
+++ b/spec/models/project_services/emails_on_push_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe EmailsOnPushService do
diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb
index 62fd97b038b..bdd8605436f 100644
--- a/spec/models/project_services/external_wiki_service_spec.rb
+++ b/spec/models/project_services/external_wiki_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ExternalWikiService do
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index fabcb142858..c1ebe69ee66 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe FlowdockService do
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index 3237b660a16..11f96c03d46 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GitlabIssueTrackerService do
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
index cb9ca76fc3f..2e1f6964692 100644
--- a/spec/models/project_services/irker_service_spec.rb
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
require 'socket'
require 'json'
diff --git a/spec/models/project_services/issue_tracker_service_spec.rb b/spec/models/project_services/issue_tracker_service_spec.rb
index e6a1752576b..2fc4d69c2db 100644
--- a/spec/models/project_services/issue_tracker_service_spec.rb
+++ b/spec/models/project_services/issue_tracker_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe IssueTrackerService do
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 5428fcb1271..4a7eee1fbf3 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe JiraService do
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 56e587262ef..7bf093b71e7 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe KubernetesService, :use_clean_rails_memory_store_caching do
diff --git a/spec/models/project_services/mattermost_service_spec.rb b/spec/models/project_services/mattermost_service_spec.rb
index 10c62ca55a7..6261c70f266 100644
--- a/spec/models/project_services/mattermost_service_spec.rb
+++ b/spec/models/project_services/mattermost_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MattermostService do
diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
index 1983e0cc967..87e482059f2 100644
--- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb
+++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MattermostSlashCommandsService do
diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb
index 3351c6280b4..521d5265753 100644
--- a/spec/models/project_services/microsoft_teams_service_spec.rb
+++ b/spec/models/project_services/microsoft_teams_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MicrosoftTeamsService do
diff --git a/spec/models/project_services/packagist_service_spec.rb b/spec/models/project_services/packagist_service_spec.rb
index 6acee311700..53f18a1bdd9 100644
--- a/spec/models/project_services/packagist_service_spec.rb
+++ b/spec/models/project_services/packagist_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PackagistService do
diff --git a/spec/models/project_services/pipelines_email_service_spec.rb b/spec/models/project_services/pipelines_email_service_spec.rb
index 75ae2207910..ca17e7453b8 100644
--- a/spec/models/project_services/pipelines_email_service_spec.rb
+++ b/spec/models/project_services/pipelines_email_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelinesEmailService, :mailer do
diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb
index f7d2372eca2..de2c8790405 100644
--- a/spec/models/project_services/pivotaltracker_service_spec.rb
+++ b/spec/models/project_services/pivotaltracker_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PivotaltrackerService do
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index 54b8c658ff6..d2a45f48705 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PushoverService do
diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb
index 2ac14eab5e1..ac570ac27e1 100644
--- a/spec/models/project_services/redmine_service_spec.rb
+++ b/spec/models/project_services/redmine_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RedmineService do
diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb
index 13cf4d1915e..01f580c5d01 100644
--- a/spec/models/project_services/slack_service_spec.rb
+++ b/spec/models/project_services/slack_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SlackService do
diff --git a/spec/models/project_services/slack_slash_commands_service_spec.rb b/spec/models/project_services/slack_slash_commands_service_spec.rb
index 5c4bce90ace..8c57907d064 100644
--- a/spec/models/project_services/slack_slash_commands_service_spec.rb
+++ b/spec/models/project_services/slack_slash_commands_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SlackSlashCommandsService do
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
index 64b4efca43a..96dccae733b 100644
--- a/spec/models/project_services/teamcity_service_spec.rb
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TeamcityService, :use_clean_rails_memory_store_caching do
diff --git a/spec/models/project_services/youtrack_service_spec.rb b/spec/models/project_services/youtrack_service_spec.rb
index 9524b526a46..bf9d892f66c 100644
--- a/spec/models/project_services/youtrack_service_spec.rb
+++ b/spec/models/project_services/youtrack_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe YoutrackService do
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
index 1b439bcfad1..e87b4f41f4d 100644
--- a/spec/models/project_snippet_spec.rb
+++ b/spec/models/project_snippet_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectSnippet do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 90dcf861849..2158d3cf3e6 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Project do
diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb
index 64c39f09e33..c670b6aac56 100644
--- a/spec/models/project_statistics_spec.rb
+++ b/spec/models/project_statistics_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe ProjectStatistics do
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 3537dead5d1..a2d4fad9292 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe ProjectTeam do
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 7be8d67ba9e..7ea67f31534 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -1,4 +1,6 @@
# coding: utf-8
+# frozen_string_literal: true
+
require "spec_helper"
describe ProjectWiki do
diff --git a/spec/models/protectable_dropdown_spec.rb b/spec/models/protectable_dropdown_spec.rb
index d4433a88a15..aca3df9fdde 100644
--- a/spec/models/protectable_dropdown_spec.rb
+++ b/spec/models/protectable_dropdown_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProtectableDropdown do
diff --git a/spec/models/protected_branch/merge_access_level_spec.rb b/spec/models/protected_branch/merge_access_level_spec.rb
index 612e4a0e332..39dd586b157 100644
--- a/spec/models/protected_branch/merge_access_level_spec.rb
+++ b/spec/models/protected_branch/merge_access_level_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProtectedBranch::MergeAccessLevel do
diff --git a/spec/models/protected_branch/push_access_level_spec.rb b/spec/models/protected_branch/push_access_level_spec.rb
index 9ccdc22fd41..628c8d29ecd 100644
--- a/spec/models/protected_branch/push_access_level_spec.rb
+++ b/spec/models/protected_branch/push_access_level_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProtectedBranch::PushAccessLevel do
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index dafe7646366..267434a4148 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProtectedBranch do
diff --git a/spec/models/protected_tag_spec.rb b/spec/models/protected_tag_spec.rb
index e5a0f6ec23f..79120d17d39 100644
--- a/spec/models/protected_tag_spec.rb
+++ b/spec/models/protected_tag_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProtectedTag do
diff --git a/spec/models/push_event_payload_spec.rb b/spec/models/push_event_payload_spec.rb
index 69a4922b6fd..6b59ee5ee57 100644
--- a/spec/models/push_event_payload_spec.rb
+++ b/spec/models/push_event_payload_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PushEventPayload do
diff --git a/spec/models/push_event_spec.rb b/spec/models/push_event_spec.rb
index bfe7a30b96a..f86500f91cd 100644
--- a/spec/models/push_event_spec.rb
+++ b/spec/models/push_event_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PushEvent do
diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb
index 106ae59af29..6ecb5c31c7e 100644
--- a/spec/models/redirect_route_spec.rb
+++ b/spec/models/redirect_route_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe RedirectRoute do
diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb
index 157c96c1f65..b4b32c95dee 100644
--- a/spec/models/release_spec.rb
+++ b/spec/models/release_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
RSpec.describe Release do
diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb
index c06e9a08ab4..0478094034a 100644
--- a/spec/models/remote_mirror_spec.rb
+++ b/spec/models/remote_mirror_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe RemoteMirror, :mailer do
diff --git a/spec/models/repository_language_spec.rb b/spec/models/repository_language_spec.rb
index e2e4beb512f..13a4cd1e7cf 100644
--- a/spec/models/repository_language_spec.rb
+++ b/spec/models/repository_language_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryLanguage do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 6599b4e765a..2578208659a 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Repository do
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index 48799781b87..20289afbeb5 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Route do
diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb
index 6c35ed8f649..09be90b82ed 100644
--- a/spec/models/sent_notification_spec.rb
+++ b/spec/models/sent_notification_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SentNotification do
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 25eecb3f909..2f025038bab 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Service do
diff --git a/spec/models/snippet_blob_spec.rb b/spec/models/snippet_blob_spec.rb
index 7c71c458fcc..88441e39d45 100644
--- a/spec/models/snippet_blob_spec.rb
+++ b/spec/models/snippet_blob_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SnippetBlob do
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 664dc3fa145..3524cdae3b8 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Snippet do
diff --git a/spec/models/spam_log_spec.rb b/spec/models/spam_log_spec.rb
index 90a2caaeb88..e9ea234f75d 100644
--- a/spec/models/spam_log_spec.rb
+++ b/spec/models/spam_log_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SpamLog do
diff --git a/spec/models/ssh_host_key_spec.rb b/spec/models/ssh_host_key_spec.rb
index 4c677569561..a17cd8ba345 100644
--- a/spec/models/ssh_host_key_spec.rb
+++ b/spec/models/ssh_host_key_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SshHostKey do
diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb
index 9e4c2620d82..41bd48810b2 100644
--- a/spec/models/subscription_spec.rb
+++ b/spec/models/subscription_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Subscription do
diff --git a/spec/models/system_note_metadata_spec.rb b/spec/models/system_note_metadata_spec.rb
index 1e3f587e460..bcd3c03f947 100644
--- a/spec/models/system_note_metadata_spec.rb
+++ b/spec/models/system_note_metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SystemNoteMetadata do
diff --git a/spec/models/term_agreement_spec.rb b/spec/models/term_agreement_spec.rb
index 950dfa09a6a..42a48048b67 100644
--- a/spec/models/term_agreement_spec.rb
+++ b/spec/models/term_agreement_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TermAgreement do
diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb
index a0c93c531ea..9d69a0ab148 100644
--- a/spec/models/timelog_spec.rb
+++ b/spec/models/timelog_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
RSpec.describe Timelog do
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 3682e21ca40..b5bf294790a 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Todo do
diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb
index 6bdb62a0864..c2d5dfdf9c4 100644
--- a/spec/models/tree_spec.rb
+++ b/spec/models/tree_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Tree do
diff --git a/spec/models/trending_project_spec.rb b/spec/models/trending_project_spec.rb
index 3b5e7ca0d39..619fc8e7d38 100644
--- a/spec/models/trending_project_spec.rb
+++ b/spec/models/trending_project_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TrendingProject do
diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb
index 5a0df9fbbb0..02702cb2497 100644
--- a/spec/models/upload_spec.rb
+++ b/spec/models/upload_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe Upload do
diff --git a/spec/models/user_agent_detail_spec.rb b/spec/models/user_agent_detail_spec.rb
index b4669f8c1c2..f191d245045 100644
--- a/spec/models/user_agent_detail_spec.rb
+++ b/spec/models/user_agent_detail_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe UserAgentDetail do
diff --git a/spec/models/user_callout_spec.rb b/spec/models/user_callout_spec.rb
index d54355afe12..b87f6f03d6f 100644
--- a/spec/models/user_callout_spec.rb
+++ b/spec/models/user_callout_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe UserCallout do
diff --git a/spec/models/user_custom_attribute_spec.rb b/spec/models/user_custom_attribute_spec.rb
index 37fc3cb64f0..d0981b2d771 100644
--- a/spec/models/user_custom_attribute_spec.rb
+++ b/spec/models/user_custom_attribute_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe UserCustomAttribute do
diff --git a/spec/models/user_interacted_project_spec.rb b/spec/models/user_interacted_project_spec.rb
index cb4bb3372d4..47d919c1d12 100644
--- a/spec/models/user_interacted_project_spec.rb
+++ b/spec/models/user_interacted_project_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe UserInteractedProject do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 1be29d039a7..b7e36748fa2 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe User do
diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb
index fb8575cfe2b..5fbcccf897e 100644
--- a/spec/models/wiki_directory_spec.rb
+++ b/spec/models/wiki_directory_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
RSpec.describe WikiDirectory do
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index cba22b2cc4e..e68da67818a 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe WikiPage do
diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb
index f50bcf54b46..ad6cb012d0b 100644
--- a/spec/presenters/ci/build_runner_presenter_spec.rb
+++ b/spec/presenters/ci/build_runner_presenter_spec.rb
@@ -136,6 +136,24 @@ describe Ci::BuildRunnerPresenter do
is_expected.to eq(1)
end
end
+
+ context 'when pipeline is detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
+ let(:pipeline) { merge_request.all_pipelines.first }
+ let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) }
+
+ it 'returns the default git depth for pipelines for merge requests' do
+ is_expected.to eq(described_class::DEFAULT_GIT_DEPTH_MERGE_REQUEST)
+ end
+
+ context 'when pipeline is legacy detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
+
+ it 'behaves as branch pipeline' do
+ is_expected.to eq(0)
+ end
+ end
+ end
end
describe '#refspecs' do
@@ -165,5 +183,25 @@ describe Ci::BuildRunnerPresenter do
end
end
end
+
+ context 'when pipeline is detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
+ let(:pipeline) { merge_request.all_pipelines.first }
+ let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) }
+
+ it 'returns the correct refspecs' do
+ is_expected
+ .to contain_exactly('+refs/merge-requests/1/head:refs/merge-requests/1/head')
+ end
+
+ context 'when pipeline is legacy detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
+
+ it 'returns the correct refspecs' do
+ is_expected.to contain_exactly('+refs/tags/*:refs/tags/*',
+ '+refs/heads/*:refs/remotes/origin/*')
+ end
+ end
+ end
end
end
diff --git a/spec/presenters/clusters/cluster_presenter_spec.rb b/spec/presenters/clusters/cluster_presenter_spec.rb
index 754ba0a594c..a9d786bc872 100644
--- a/spec/presenters/clusters/cluster_presenter_spec.rb
+++ b/spec/presenters/clusters/cluster_presenter_spec.rb
@@ -228,4 +228,20 @@ describe Clusters::ClusterPresenter do
it { is_expected.to eq(group_cluster_path(group, cluster)) }
end
end
+
+ describe '#read_only_kubernetes_platform_fields?' do
+ subject { described_class.new(cluster).read_only_kubernetes_platform_fields? }
+
+ context 'with a user-provided cluster' do
+ let(:cluster) { build_stubbed(:cluster, :provided_by_user) }
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'with a GCP-provided cluster' do
+ let(:cluster) { build_stubbed(:cluster, :provided_by_gcp) }
+
+ it { is_expected.to be_truthy }
+ end
+ end
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index b38cd66986f..8b503777443 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -20,9 +20,9 @@ describe API::Branches do
let(:route) { "/projects/#{project_id}/repository/branches" }
shared_examples_for 'repository branches' do
- RSpec::Matchers.define :has_merged_branch_names_count do |expected|
+ RSpec::Matchers.define :has_up_to_merged_branch_names_count do |expected|
match do |actual|
- actual[:merged_branch_names].count == expected
+ expected >= actual[:merged_branch_names].count
end
end
@@ -36,10 +36,30 @@ describe API::Branches do
expect(branch_names).to match_array(project.repository.branch_names)
end
+ def check_merge_status(json_response)
+ merged, unmerged = json_response.partition { |branch| branch['merged'] }
+ merged_branches = merged.map { |branch| branch['name'] }
+ unmerged_branches = unmerged.map { |branch| branch['name'] }
+ expect(Set.new(merged_branches)).to eq(project.repository.merged_branch_names(merged_branches + unmerged_branches))
+ expect(project.repository.merged_branch_names(unmerged_branches)).to be_empty
+ end
+
it 'determines only a limited number of merged branch names' do
- expect(API::Entities::Branch).to receive(:represent).with(anything, has_merged_branch_names_count(2))
+ expect(API::Entities::Branch).to receive(:represent).with(anything, has_up_to_merged_branch_names_count(2)).and_call_original
get api(route, current_user), params: { per_page: 2 }
+
+ expect(response).to have_gitlab_http_status(200)
+
+ check_merge_status(json_response)
+ end
+
+ it 'merge status matches reality on paginated input' do
+ get api(route, current_user), params: { per_page: 20, page: 2 }
+
+ expect(response).to have_gitlab_http_status(200)
+
+ check_merge_status(json_response)
end
context 'when repository is disabled' do
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index 4e42e233b4c..81442125a1c 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -60,7 +60,7 @@ describe API::ProjectClusters do
end
let(:cluster) do
- create(:cluster, :project, :provided_by_gcp,
+ create(:cluster, :project, :provided_by_gcp, :with_domain,
platform_kubernetes: platform_kubernetes,
user: current_user,
projects: [project])
@@ -88,6 +88,7 @@ describe API::ProjectClusters do
expect(json_response['platform_type']).to eq('kubernetes')
expect(json_response['environment_scope']).to eq('*')
expect(json_response['cluster_type']).to eq('project_type')
+ expect(json_response['domain']).to eq('example.com')
end
it 'returns project information' do
@@ -187,6 +188,7 @@ describe API::ProjectClusters do
let(:cluster_params) do
{
name: 'test-cluster',
+ domain: 'domain.example.com',
platform_kubernetes_attributes: platform_kubernetes_attributes
}
end
@@ -217,6 +219,7 @@ describe API::ProjectClusters do
expect(cluster_result).to be_kubernetes
expect(cluster_result.project).to eq(project)
expect(cluster_result.name).to eq('test-cluster')
+ expect(cluster_result.domain).to eq('domain.example.com')
expect(platform_kubernetes.rbac?).to be_truthy
expect(platform_kubernetes.api_url).to eq(api_url)
expect(platform_kubernetes.namespace).to eq(namespace)
@@ -294,6 +297,7 @@ describe API::ProjectClusters do
let(:update_params) do
{
+ domain: 'new-domain.com',
platform_kubernetes_attributes: platform_kubernetes_attributes
}
end
@@ -330,6 +334,7 @@ describe API::ProjectClusters do
end
it 'should update cluster attributes' do
+ expect(cluster.domain).to eq('new-domain.com')
expect(cluster.platform_kubernetes.namespace).to eq('new-namespace')
end
end
@@ -342,6 +347,7 @@ describe API::ProjectClusters do
end
it 'should not update cluster attributes' do
+ expect(cluster.domain).not_to eq('new_domain.com')
expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace')
expect(cluster.kubernetes_namespace.namespace).not_to eq('invalid_namespace')
end
diff --git a/spec/services/error_tracking/list_issues_service_spec.rb b/spec/services/error_tracking/list_issues_service_spec.rb
index 9d4fc62f923..3a8f3069911 100644
--- a/spec/services/error_tracking/list_issues_service_spec.rb
+++ b/spec/services/error_tracking/list_issues_service_spec.rb
@@ -53,7 +53,10 @@ describe ErrorTracking::ListIssuesService do
before do
allow(error_tracking_setting)
.to receive(:list_sentry_issues)
- .and_return(error: 'Sentry response status code: 401')
+ .and_return(
+ error: 'Sentry response status code: 401',
+ error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_NON_20X_RESPONSE
+ )
end
it 'returns the error' do
@@ -64,6 +67,25 @@ describe ErrorTracking::ListIssuesService do
)
end
end
+
+ context 'when list_sentry_issues returns error with http_status' do
+ before do
+ allow(error_tracking_setting)
+ .to receive(:list_sentry_issues)
+ .and_return(
+ error: 'Sentry API response is missing keys. key not found: "id"',
+ error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_MISSING_KEYS
+ )
+ end
+
+ it 'returns the error with correct http_status' do
+ expect(result).to eq(
+ status: :error,
+ http_status: :internal_server_error,
+ message: 'Sentry API response is missing keys. key not found: "id"'
+ )
+ end
+ end
end
context 'with unauthorized user' do
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 715b1168bfb..d50412b6d2c 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -138,6 +138,20 @@ describe Issues::CreateService do
end
end
+ context 'when duplicate label titles are given' do
+ let(:label) { create(:label, project: project) }
+
+ let(:opts) do
+ { title: 'Title',
+ description: 'Description',
+ labels: [label.title, label.title] }
+ end
+
+ it 'assigns the label once' do
+ expect(issue.labels).to contain_exactly(label)
+ end
+ end
+
it 'executes issue hooks when issue is not confidential' do
opts = { title: 'Title', description: 'Description', confidential: false }
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index f1684209729..1c8a4b608d5 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -592,6 +592,16 @@ describe Issues::UpdateService, :mailer do
expect(result.label_ids).not_to include(label.id)
end
end
+
+ context 'when duplicate label titles are given' do
+ let(:params) do
+ { labels: [label3.title, label3.title] }
+ end
+
+ it 'assigns the label once' do
+ expect(result.labels).to contain_exactly(label3)
+ end
+ end
end
context 'updating asssignee_id' do
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index a04a4d5fc36..55e7b46248b 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -173,7 +173,7 @@ describe MergeRequests::CreateService do
end
end
- describe 'Merge request pipelines' do
+ describe 'Pipelines for merge requests' do
before do
stub_ci_pipeline_yaml_file(YAML.dump(config))
end
@@ -189,12 +189,46 @@ describe MergeRequests::CreateService do
}
end
- it 'creates a merge request pipeline and sets it as a head pipeline' do
+ it 'creates a detached merge request pipeline and sets it as a head pipeline' do
expect(merge_request).to be_persisted
merge_request.reload
expect(merge_request.merge_request_pipelines.count).to eq(1)
- expect(merge_request.actual_head_pipeline).to be_merge_request_event
+ expect(merge_request.actual_head_pipeline).to be_detached_merge_request_pipeline
+ end
+
+ context 'when merge request is submitted from forked project' do
+ let(:target_project) { fork_project(project, nil, repository: true) }
+
+ let(:opts) do
+ {
+ title: 'Awesome merge_request',
+ source_branch: 'feature',
+ target_branch: 'master',
+ target_project_id: target_project.id
+ }
+ end
+
+ before do
+ target_project.add_developer(assignee)
+ target_project.add_maintainer(user)
+ end
+
+ it 'create legacy detached merge request pipeline for fork merge request' do
+ expect(merge_request.actual_head_pipeline)
+ .to be_legacy_detached_merge_request_pipeline
+ end
+ end
+
+ context 'when ci_use_merge_request_ref feature flag is false' do
+ before do
+ stub_feature_flags(ci_use_merge_request_ref: false)
+ end
+
+ it 'create legacy detached merge request pipeline for non-fork merge request' do
+ expect(merge_request.actual_head_pipeline)
+ .to be_legacy_detached_merge_request_pipeline
+ end
end
context 'when there are no commits between source branch and target branch' do
@@ -207,7 +241,7 @@ describe MergeRequests::CreateService do
}
end
- it 'does not create a merge request pipeline' do
+ it 'does not create a detached merge request pipeline' do
expect(merge_request).to be_persisted
merge_request.reload
@@ -225,7 +259,7 @@ describe MergeRequests::CreateService do
merge_request
end
- it 'sets the latest merge request pipeline as the head pipeline' do
+ it 'sets the latest detached merge request pipeline as the head pipeline' do
expect(merge_request.actual_head_pipeline).to be_merge_request_event
end
end
@@ -235,7 +269,7 @@ describe MergeRequests::CreateService do
stub_feature_flags(ci_merge_request_pipeline: false)
end
- it 'does not create a merge request pipeline' do
+ it 'does not create a detached merge request pipeline' do
expect(merge_request).to be_persisted
merge_request.reload
@@ -254,7 +288,7 @@ describe MergeRequests::CreateService do
}
end
- it 'does not create a merge request pipeline' do
+ it 'does not create a detached merge request pipeline' do
expect(merge_request).to be_persisted
merge_request.reload
diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb
index fabca8f6b4a..a3b48abae26 100644
--- a/spec/services/merge_requests/merge_to_ref_service_spec.rb
+++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb
@@ -40,15 +40,6 @@ describe MergeRequests::MergeToRefService do
end
shared_examples_for 'successfully evaluates pre-condition checks' do
- it 'returns error when feature is disabled' do
- stub_feature_flags(merge_to_tmp_merge_ref_path: false)
-
- result = service.execute(merge_request)
-
- expect(result[:status]).to eq(:error)
- expect(result[:message]).to eq('Feature is not enabled')
- end
-
it 'returns an error when the failing to process the merge' do
allow(project.repository).to receive(:merge_to_ref).and_return(nil)
@@ -180,6 +171,17 @@ describe MergeRequests::MergeToRefService do
it { expect(todo).not_to be_done }
end
+ context 'when merge request is WIP state' do
+ it 'fails to merge' do
+ merge_request = create(:merge_request, title: 'WIP: The feature')
+
+ result = service.execute(merge_request)
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq("Merge request is not mergeable to #{merge_request.merge_ref_path}")
+ end
+ end
+
it 'returns error when user has no authorization to admin the merge request' do
unauthorized_user = create(:user)
project.add_reporter(unauthorized_user)
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 6c8ff163692..25cbac6d7ee 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -141,7 +141,7 @@ describe MergeRequests::RefreshService do
end
end
- describe 'Merge request pipelines' do
+ describe 'Pipelines for merge requests' do
before do
stub_ci_pipeline_yaml_file(YAML.dump(config))
end
@@ -159,7 +159,7 @@ describe MergeRequests::RefreshService do
}
end
- it 'create merge request pipeline with commits' do
+ it 'create detached merge request pipeline with commits' do
expect { subject }
.to change { @merge_request.merge_request_pipelines.count }.by(1)
.and change { @fork_merge_request.merge_request_pipelines.count }.by(1)
@@ -170,7 +170,34 @@ describe MergeRequests::RefreshService do
expect(@another_merge_request.has_commits?).to be_falsy
end
- context "when branch pipeline was created before a merge request pipline has been created" do
+ it 'create detached merge request pipeline for non-fork merge request' do
+ subject
+
+ expect(@merge_request.merge_request_pipelines.first)
+ .to be_detached_merge_request_pipeline
+ end
+
+ it 'create legacy detached merge request pipeline for fork merge request' do
+ subject
+
+ expect(@fork_merge_request.merge_request_pipelines.first)
+ .to be_legacy_detached_merge_request_pipeline
+ end
+
+ context 'when ci_use_merge_request_ref feature flag is false' do
+ before do
+ stub_feature_flags(ci_use_merge_request_ref: false)
+ end
+
+ it 'create legacy detached merge request pipeline for non-fork merge request' do
+ subject
+
+ expect(@merge_request.merge_request_pipelines.first)
+ .to be_legacy_detached_merge_request_pipeline
+ end
+ end
+
+ context "when branch pipeline was created before a detaced merge request pipeline has been created" do
before do
create(:ci_pipeline, project: @merge_request.source_project,
sha: @merge_request.diff_head_sha,
@@ -180,7 +207,7 @@ describe MergeRequests::RefreshService do
subject
end
- it 'sets the latest merge request pipeline as a head pipeline' do
+ it 'sets the latest detached merge request pipeline as a head pipeline' do
@merge_request.reload
expect(@merge_request.actual_head_pipeline).to be_merge_request_event
end
@@ -193,7 +220,7 @@ describe MergeRequests::RefreshService do
end
context "when MergeRequestUpdateWorker is retried by an exception" do
- it 'does not re-create a duplicate merge request pipeline' do
+ it 'does not re-create a duplicate detached merge request pipeline' do
expect do
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master')
end.to change { @merge_request.merge_request_pipelines.count }.by(1)
@@ -209,7 +236,7 @@ describe MergeRequests::RefreshService do
stub_feature_flags(ci_merge_request_pipeline: false)
end
- it 'does not create a merge request pipeline' do
+ it 'does not create a detached merge request pipeline' do
expect { subject }
.not_to change { @merge_request.merge_request_pipelines.count }
end
@@ -226,7 +253,7 @@ describe MergeRequests::RefreshService do
}
end
- it 'does not create a merge request pipeline' do
+ it 'does not create a detached merge request pipeline' do
expect { subject }
.not_to change { @merge_request.merge_request_pipelines.count }
end
diff --git a/spec/services/projects/after_import_service_spec.rb b/spec/services/projects/after_import_service_spec.rb
index 4dd6c6dab86..765b4ffae8f 100644
--- a/spec/services/projects/after_import_service_spec.rb
+++ b/spec/services/projects/after_import_service_spec.rb
@@ -13,7 +13,7 @@ describe Projects::AfterImportService do
describe '#execute' do
before do
allow(Projects::HousekeepingService)
- .to receive(:new).with(project).and_return(housekeeping_service)
+ .to receive(:new).with(project, :gc).and_return(housekeeping_service)
allow(housekeeping_service)
.to receive(:execute).and_yield
diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb
index 18ecef1c0a1..12ae9105627 100644
--- a/spec/services/projects/housekeeping_service_spec.rb
+++ b/spec/services/projects/housekeeping_service_spec.rb
@@ -88,6 +88,19 @@ describe Projects::HousekeepingService do
expect(project.pushes_since_gc).to eq(1)
end
end
+
+ it 'runs the task specifically requested' do
+ housekeeping = described_class.new(project, :gc)
+
+ allow(housekeeping).to receive(:try_obtain_lease).and_return(:gc_uuid)
+ allow(housekeeping).to receive(:lease_key).and_return(:gc_lease_key)
+
+ expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :gc, :gc_lease_key, :gc_uuid).twice
+
+ 2.times do
+ housekeeping.execute
+ end
+ end
end
describe '#needed?' do
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index ea33d156c8a..8b0f9c8ade2 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -15,6 +15,7 @@ describe QuickActions::InterpretService do
let(:service) { described_class.new(project, developer) }
before do
+ stub_licensed_features(multiple_issue_assignees: false)
project.add_developer(developer)
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index b3bd453ebd6..60db3e1bc46 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -66,6 +66,7 @@ RSpec.configure do |config|
metadata[:type] = match[1].singularize.to_sym if match
end
+ config.include LicenseHelpers
config.include ActiveJob::TestHelper
config.include ActiveSupport::Testing::TimeHelpers
config.include CycleAnalyticsHelpers
diff --git a/spec/support/features/issuable_quick_actions_shared_examples.rb b/spec/support/features/issuable_quick_actions_shared_examples.rb
deleted file mode 100644
index 2a883ce1074..00000000000
--- a/spec/support/features/issuable_quick_actions_shared_examples.rb
+++ /dev/null
@@ -1,389 +0,0 @@
-# Specifications for behavior common to all objects with executable attributes.
-# It takes a `issuable_type`, and expect an `issuable`.
-
-shared_examples 'issuable record that supports quick actions in its description and notes' do |issuable_type|
- include Spec::Support::Helpers::Features::NotesHelpers
-
- let(:maintainer) { create(:user) }
- let(:project) do
- case issuable_type
- when :merge_request
- create(:project, :public, :repository)
- when :issue
- create(:project, :public)
- end
- end
- let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
- let!(:label_bug) { create(:label, project: project, title: 'bug') }
- let!(:label_feature) { create(:label, project: project, title: 'feature') }
- let(:new_url_opts) { {} }
-
- before do
- project.add_maintainer(maintainer)
-
- gitlab_sign_in(maintainer)
- end
-
- after do
- # Ensure all outstanding Ajax requests are complete to avoid database deadlocks
- wait_for_requests
- end
-
- describe "new #{issuable_type}", :js do
- context 'with commands in the description' do
- it "creates the #{issuable_type} and interpret commands accordingly" do
- case issuable_type
- when :merge_request
- visit public_send("namespace_project_new_merge_request_path", project.namespace, project, new_url_opts)
- when :issue
- visit public_send("new_namespace_project_issue_path", project.namespace, project, new_url_opts)
- end
- fill_in "#{issuable_type}_title", with: 'bug 345'
- fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug\n/milestone %\"ASAP\""
- click_button "Submit #{issuable_type}".humanize
-
- issuable = project.public_send(issuable_type.to_s.pluralize).first
-
- expect(issuable.description).to eq "bug description"
- expect(issuable.labels).to eq [label_bug]
- expect(issuable.milestone).to eq milestone
- expect(page).to have_content 'bug 345'
- expect(page).to have_content 'bug description'
- end
- end
- end
-
- describe "note on #{issuable_type}", :js do
- before do
- visit public_send("project_#{issuable_type}_path", project, issuable)
- end
-
- context 'with a note containing commands' do
- it 'creates a note without the commands and interpret the commands accordingly' do
- assignee = create(:user, username: 'bob')
- add_note("Awesome!\n\n/assign @bob\n\n/label ~bug\n\n/milestone %\"ASAP\"")
-
- expect(page).to have_content 'Awesome!'
- expect(page).not_to have_content '/assign @bob'
- expect(page).not_to have_content '/label ~bug'
- expect(page).not_to have_content '/milestone %"ASAP"'
-
- wait_for_requests
- issuable.reload
- note = issuable.notes.user.first
-
- expect(note.note).to eq "Awesome!"
- expect(issuable.assignees).to eq [assignee]
- expect(issuable.labels).to eq [label_bug]
- expect(issuable.milestone).to eq milestone
- end
-
- it 'removes the quick action from note and explains it in the preview' do
- preview_note("Awesome!\n\n/close")
-
- expect(page).to have_content 'Awesome!'
- expect(page).not_to have_content '/close'
- issuable_name = issuable.is_a?(Issue) ? 'issue' : 'merge request'
- expect(page).to have_content "Closes this #{issuable_name}."
- end
- end
-
- context 'with a note containing only commands' do
- it 'does not create a note but interpret the commands accordingly' do
- assignee = create(:user, username: 'bob')
- add_note("/assign @bob\n\n/label ~bug\n\n/milestone %\"ASAP\"")
-
- expect(page).not_to have_content '/assign @bob'
- expect(page).not_to have_content '/label ~bug'
- expect(page).not_to have_content '/milestone %"ASAP"'
- expect(page).to have_content 'Commands applied'
-
- issuable.reload
-
- expect(issuable.notes.user).to be_empty
- expect(issuable.assignees).to eq [assignee]
- expect(issuable.labels).to eq [label_bug]
- expect(issuable.milestone).to eq milestone
- end
- end
-
- context "with a note closing the #{issuable_type}" do
- before do
- expect(issuable).to be_open
- end
-
- context "when current user can close #{issuable_type}" do
- it "closes the #{issuable_type}" do
- add_note("/close")
-
- expect(page).not_to have_content '/close'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.reload).to be_closed
- end
- end
-
- context "when current user cannot close #{issuable_type}" do
- before do
- guest = create(:user)
- project.add_guest(guest)
-
- gitlab_sign_out
- gitlab_sign_in(guest)
- visit public_send("project_#{issuable_type}_path", project, issuable)
- end
-
- it "does not close the #{issuable_type}" do
- add_note("/close")
-
- expect(page).not_to have_content 'Commands applied'
-
- expect(issuable).to be_open
- end
- end
- end
-
- context "with a note reopening the #{issuable_type}" do
- before do
- issuable.close
- expect(issuable).to be_closed
- end
-
- context "when current user can reopen #{issuable_type}" do
- it "reopens the #{issuable_type}" do
- add_note("/reopen")
-
- expect(page).not_to have_content '/reopen'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.reload).to be_open
- end
- end
-
- context "when current user cannot reopen #{issuable_type}" do
- before do
- guest = create(:user)
- project.add_guest(guest)
-
- gitlab_sign_out
- gitlab_sign_in(guest)
- visit public_send("project_#{issuable_type}_path", project, issuable)
- end
-
- it "does not reopen the #{issuable_type}" do
- add_note("/reopen")
-
- expect(page).not_to have_content 'Commands applied'
-
- expect(issuable).to be_closed
- end
- end
- end
-
- context "with a note changing the #{issuable_type}'s title" do
- context "when current user can change title of #{issuable_type}" do
- it "reopens the #{issuable_type}" do
- add_note("/title Awesome new title")
-
- expect(page).not_to have_content '/title'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.reload.title).to eq 'Awesome new title'
- end
- end
-
- context "when current user cannot change title of #{issuable_type}" do
- before do
- guest = create(:user)
- project.add_guest(guest)
-
- gitlab_sign_out
- gitlab_sign_in(guest)
- visit public_send("project_#{issuable_type}_path", project, issuable)
- end
-
- it "does not change the #{issuable_type} title" do
- add_note("/title Awesome new title")
-
- expect(page).not_to have_content 'Commands applied'
-
- expect(issuable.reload.title).not_to eq 'Awesome new title'
- end
- end
- end
-
- context "with a note marking the #{issuable_type} as todo" do
- it "creates a new todo for the #{issuable_type}" do
- add_note("/todo")
-
- expect(page).not_to have_content '/todo'
- expect(page).to have_content 'Commands applied'
-
- todos = TodosFinder.new(maintainer).execute
- todo = todos.first
-
- expect(todos.size).to eq 1
- expect(todo).to be_pending
- expect(todo.target).to eq issuable
- expect(todo.author).to eq maintainer
- expect(todo.user).to eq maintainer
- end
- end
-
- context "with a note marking the #{issuable_type} as done" do
- before do
- TodoService.new.mark_todo(issuable, maintainer)
- end
-
- it "creates a new todo for the #{issuable_type}" do
- todos = TodosFinder.new(maintainer).execute
- todo = todos.first
-
- expect(todos.size).to eq 1
- expect(todos.first).to be_pending
- expect(todo.target).to eq issuable
- expect(todo.author).to eq maintainer
- expect(todo.user).to eq maintainer
-
- add_note("/done")
-
- expect(page).not_to have_content '/done'
- expect(page).to have_content 'Commands applied'
-
- expect(todo.reload).to be_done
- end
- end
-
- context "with a note subscribing to the #{issuable_type}" do
- it "creates a new todo for the #{issuable_type}" do
- expect(issuable.subscribed?(maintainer, project)).to be_falsy
-
- add_note("/subscribe")
-
- expect(page).not_to have_content '/subscribe'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.subscribed?(maintainer, project)).to be_truthy
- end
- end
-
- context "with a note unsubscribing to the #{issuable_type} as done" do
- before do
- issuable.subscribe(maintainer, project)
- end
-
- it "creates a new todo for the #{issuable_type}" do
- expect(issuable.subscribed?(maintainer, project)).to be_truthy
-
- add_note("/unsubscribe")
-
- expect(page).not_to have_content '/unsubscribe'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.subscribed?(maintainer, project)).to be_falsy
- end
- end
-
- context "with a note assigning the #{issuable_type} to the current user" do
- it "assigns the #{issuable_type} to the current user" do
- add_note("/assign me")
-
- expect(page).not_to have_content '/assign me'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.reload.assignees).to eq [maintainer]
- end
- end
-
- context "with a note locking the #{issuable_type} discussion" do
- before do
- issuable.update(discussion_locked: false)
- expect(issuable).not_to be_discussion_locked
- end
-
- context "when current user can lock #{issuable_type} discussion" do
- it "locks the #{issuable_type} discussion" do
- add_note("/lock")
-
- expect(page).not_to have_content '/lock'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.reload).to be_discussion_locked
- end
- end
-
- context "when current user cannot lock #{issuable_type}" do
- before do
- guest = create(:user)
- project.add_guest(guest)
-
- gitlab_sign_out
- sign_in(guest)
- visit public_send("project_#{issuable_type}_path", project, issuable)
- end
-
- it "does not lock the #{issuable_type} discussion" do
- add_note("/lock")
-
- expect(page).not_to have_content 'Commands applied'
-
- expect(issuable).not_to be_discussion_locked
- end
- end
- end
-
- context "with a note unlocking the #{issuable_type} discussion" do
- before do
- issuable.update(discussion_locked: true)
- expect(issuable).to be_discussion_locked
- end
-
- context "when current user can unlock #{issuable_type} discussion" do
- it "unlocks the #{issuable_type} discussion" do
- add_note("/unlock")
-
- expect(page).not_to have_content '/unlock'
- expect(page).to have_content 'Commands applied'
-
- expect(issuable.reload).not_to be_discussion_locked
- end
- end
-
- context "when current user cannot unlock #{issuable_type}" do
- before do
- guest = create(:user)
- project.add_guest(guest)
-
- gitlab_sign_out
- sign_in(guest)
- visit public_send("project_#{issuable_type}_path", project, issuable)
- end
-
- it "does not unlock the #{issuable_type} discussion" do
- add_note("/unlock")
-
- expect(page).not_to have_content 'Commands applied'
-
- expect(issuable).to be_discussion_locked
- end
- end
- end
- end
-
- describe "preview of note on #{issuable_type}", :js do
- it 'removes quick actions from note and explains them' do
- create(:user, username: 'bob')
-
- visit public_send("project_#{issuable_type}_path", project, issuable)
-
- page.within('.js-main-target-form') do
- fill_in 'note[note]', with: "Awesome!\n/assign @bob "
- click_on 'Preview'
-
- expect(page).to have_content 'Awesome!'
- expect(page).not_to have_content '/assign @bob'
- expect(page).to have_content 'Assigns @bob.'
- end
- end
- end
-end
diff --git a/spec/support/helpers/license_helper.rb b/spec/support/helpers/license_helper.rb
new file mode 100644
index 00000000000..4aaad55a8ef
--- /dev/null
+++ b/spec/support/helpers/license_helper.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+# Placeholder module for EE implementation needed for CE specs to be run in EE codebase
+module LicenseHelpers
+ def stub_licensed_features(features)
+ # do nothing
+ end
+end
diff --git a/spec/support/helpers/stub_worker.rb b/spec/support/helpers/stub_worker.rb
new file mode 100644
index 00000000000..58b7ee93dff
--- /dev/null
+++ b/spec/support/helpers/stub_worker.rb
@@ -0,0 +1,9 @@
+# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb
+module StubWorker
+ def stub_worker(queue:)
+ Class.new do
+ include Sidekiq::Worker
+ sidekiq_options queue: queue
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..4604d867507
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'tag quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/assign_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/assign_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..d97da6be192
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/assign_quick_action_shared_examples.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+shared_examples 'assign quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets assign quick action accordingly" do
+ assignee = create(:user, username: 'bob')
+
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/assign @bob"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable.assignees).to eq [assignee]
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ end
+
+ it "creates the #{issuable_type} and interprets assign quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/assign me"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable.assignees).to eq [maintainer]
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the assign quick action accordingly' do
+ assignee = create(:user, username: 'bob')
+ add_note("Awesome!\n\n/assign @bob")
+
+ expect(page).to have_content 'Awesome!'
+ expect(page).not_to have_content '/assign @bob'
+
+ wait_for_requests
+ issuable.reload
+ note = issuable.notes.user.first
+
+ expect(note.note).to eq 'Awesome!'
+ expect(issuable.assignees).to eq [assignee]
+ end
+
+ it "assigns the #{issuable_type} to the current user" do
+ add_note("/assign me")
+
+ expect(page).not_to have_content '/assign me'
+ expect(page).to have_content 'Commands applied'
+
+ expect(issuable.reload.assignees).to eq [maintainer]
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains assign quick action to bob' do
+ create(:user, username: 'bob')
+
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ page.within('.js-main-target-form') do
+ fill_in 'note[note]', with: "Awesome!\n/assign @bob "
+ click_on 'Preview'
+
+ expect(page).not_to have_content '/assign @bob'
+ expect(page).to have_content 'Awesome!'
+ expect(page).to have_content 'Assigns @bob.'
+ end
+ end
+
+ it 'explains assign quick action to me' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ page.within('.js-main-target-form') do
+ fill_in 'note[note]', with: "Awesome!\n/assign me"
+ click_on 'Preview'
+
+ expect(page).not_to have_content '/assign me'
+ expect(page).to have_content 'Awesome!'
+ expect(page).to have_content "Assigns @#{maintainer.username}."
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/award_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/award_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..74cbfa3f4b4
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/award_quick_action_shared_examples.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+shared_examples 'award quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets award quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/award :100:"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.award_emoji).to eq []
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ expect(issuable.award_emoji).to eq []
+ end
+
+ it 'creates the note and interprets the award quick action accordingly' do
+ add_note("/award :100:")
+
+ wait_for_requests
+ expect(page).not_to have_content '/award'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.award_emoji.last.name).to eq('100')
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains label quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/award :100:')
+
+ expect(page).not_to have_content '/award'
+ expect(page).to have_selector "gl-emoji[data-name='100']"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..e0d0b790a0e
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+shared_examples 'close quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets close quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/close"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ expect(issuable).to be_opened
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the close quick action accordingly' do
+ add_note("this is done, close\n\n/close")
+
+ wait_for_requests
+ expect(page).not_to have_content '/close'
+ expect(page).to have_content 'this is done, close'
+
+ issuable.reload
+ note = issuable.notes.user.first
+
+ expect(note.note).to eq 'this is done, close'
+ expect(issuable).to be_closed
+ end
+
+ context "when current user cannot close #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ end
+
+ it "does not close the #{issuable_type}" do
+ add_note('/close')
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(issuable).to be_open
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains close quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ page.within('.js-main-target-form') do
+ fill_in 'note[note]', with: "this is done, close\n/close"
+ click_on 'Preview'
+
+ expect(page).not_to have_content '/close'
+ expect(page).to have_content 'this is done, close'
+ expect(page).to have_content "Closes this #{issuable_type.to_s.humanize.downcase}."
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/copy_metadata_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/copy_metadata_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..1e1e3c7bc95
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/copy_metadata_quick_action_shared_examples.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+shared_examples 'copy_metadata quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets copy_metadata quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/copy_metadata #{source_issuable.to_reference(project)}"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).last
+
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ issuable.reload
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable.milestone).to eq milestone
+ expect(issuable.labels).to match_array([label_bug, label_feature])
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets copy_metadata quick action accordingly' do
+ add_note("/copy_metadata #{source_issuable.to_reference(project)}")
+
+ wait_for_requests
+ expect(page).not_to have_content '/copy_metadata'
+ expect(page).to have_content 'Commands applied'
+ issuable.reload
+ expect(issuable.milestone).to eq milestone
+ expect(issuable.labels).to match_array([label_bug, label_feature])
+ end
+
+ context "when current user cannot copy_metadata" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not copy_metadata' do
+ add_note("/copy_metadata #{source_issuable.to_reference(project)}")
+
+ wait_for_requests
+ expect(page).not_to have_content '/copy_metadata'
+ expect(page).not_to have_content 'Commands applied'
+ issuable.reload
+ expect(issuable.milestone).not_to eq milestone
+ expect(issuable.labels).to eq []
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains copy_metadata quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note("/copy_metadata #{source_issuable.to_reference(project)}")
+
+ expect(page).not_to have_content '/copy_metadata'
+ expect(page).to have_content "Copy labels and milestone from #{source_issuable.to_reference(project)}."
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/done_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/done_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..8a72bbc13bf
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/done_quick_action_shared_examples.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+shared_examples 'done quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets done quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/done"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+
+ todos = TodosFinder.new(maintainer).execute
+ expect(todos.size).to eq 0
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ TodoService.new.mark_todo(issuable, maintainer)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the done quick action accordingly' do
+ todos = TodosFinder.new(maintainer).execute
+ todo = todos.first
+ expect(todo.reload).to be_pending
+
+ expect(todos.size).to eq 1
+ expect(todo.target).to eq issuable
+ expect(todo.author).to eq maintainer
+ expect(todo.user).to eq maintainer
+
+ add_note('/done')
+
+ wait_for_requests
+ expect(page).not_to have_content '/done'
+ expect(page).to have_content 'Commands applied'
+ expect(todo.reload).to be_done
+ end
+
+ context "when current user cannot mark #{issuable_type} todo as done" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not set the #{issuable_type} todo as done" do
+ todos = TodosFinder.new(maintainer).execute
+ todo = todos.first
+ expect(todo.reload).to be_pending
+
+ expect(todos.size).to eq 1
+ expect(todo.target).to eq issuable
+ expect(todo.author).to eq maintainer
+ expect(todo.user).to eq maintainer
+
+ add_note('/done')
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(todo.reload).to be_pending
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains done quick action' do
+ TodoService.new.mark_todo(issuable, maintainer)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/done')
+
+ expect(page).not_to have_content '/done'
+ expect(page).to have_content "Marks todo as done."
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/estimate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/estimate_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..648755d7e55
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/estimate_quick_action_shared_examples.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+shared_examples 'estimate quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets estimate quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/estimate 1d 2h 3m"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.time_estimate).to eq 36180
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the estimate quick action accordingly' do
+ add_note("/estimate 1d 2h 3m")
+
+ wait_for_requests
+ expect(page).not_to have_content '/estimate'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.time_estimate).to eq 36180
+ end
+
+ context "when current user cannot set estimate to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not set estimate' do
+ add_note("/estimate ~bug ~feature")
+
+ wait_for_requests
+ expect(page).not_to have_content '/estimate'
+ expect(issuable.reload.time_estimate).to eq 0
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains estimate quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/estimate 1d 2h 3m')
+
+ expect(page).not_to have_content '/estimate'
+ expect(page).to have_content 'Sets time estimate to 1d 2h 3m.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/label_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/label_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..9066e382b70
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/label_quick_action_shared_examples.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+shared_examples 'label quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets label quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug ~feature"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.labels).to match_array([label_bug, label_feature])
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ expect(issuable.labels).to eq []
+ end
+
+ it 'creates the note and interprets the label quick action accordingly' do
+ add_note("/label ~bug ~feature")
+
+ wait_for_requests
+ expect(page).not_to have_content '/label'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.labels).to match_array([label_bug, label_feature])
+ end
+
+ context "when current user cannot set label to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not set label' do
+ add_note("/label ~bug ~feature")
+
+ wait_for_requests
+ expect(page).not_to have_content '/label'
+ expect(issuable.labels).to eq []
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains label quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/label ~bug ~feature')
+
+ expect(page).not_to have_content '/label'
+ expect(page).to have_content 'Adds bug feature labels.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/lock_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/lock_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..d3197f2a459
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/lock_quick_action_shared_examples.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+shared_examples 'lock quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets lock quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/lock"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable).not_to be_discussion_locked
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ issuable.update(discussion_locked: false)
+ expect(issuable).not_to be_discussion_locked
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the lock quick action accordingly' do
+ add_note('/lock')
+
+ wait_for_requests
+ expect(page).not_to have_content '/lock'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload).to be_discussion_locked
+ end
+
+ context "when current user cannot lock to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not lock the #{issuable_type}" do
+ add_note('/lock')
+
+ wait_for_requests
+ expect(page).not_to have_content '/lock'
+ expect(issuable).not_to be_discussion_locked
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains lock quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/lock')
+
+ expect(page).not_to have_content '/lock'
+ expect(page).to have_content "Locks the discussion"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/milestone_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/milestone_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..7f16ce93b6a
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/milestone_quick_action_shared_examples.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+shared_examples 'milestone quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets milestone quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/milestone %\"ASAP\""
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.milestone).to eq milestone
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ expect(issuable.milestone).to be_nil
+ end
+
+ it 'creates the note and interprets the milestone quick action accordingly' do
+ add_note("/milestone %\"ASAP\"")
+
+ wait_for_requests
+ expect(page).not_to have_content '/milestone'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.milestone).to eq milestone
+ end
+
+ context "when current user cannot set milestone to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not set milestone' do
+ add_note('/milestone')
+
+ wait_for_requests
+ expect(page).not_to have_content '/milestone'
+ expect(issuable.reload.milestone).to be_nil
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains milestone quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note("/milestone %\"ASAP\"")
+
+ expect(page).not_to have_content '/milestone'
+ expect(page).to have_content 'Sets the milestone to %ASAP'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/relabel_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/relabel_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..643ae77516a
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/relabel_quick_action_shared_examples.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+shared_examples 'relabel quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets relabel quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug /relabel ~feature"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.labels).to eq [label_bug, label_feature]
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ issuable.update(labels: [label_bug])
+ end
+
+ it 'creates the note and interprets the relabel quick action accordingly' do
+ add_note('/relabel ~feature')
+
+ wait_for_requests
+ expect(page).not_to have_content '/relabel'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.labels).to match_array([label_feature])
+ end
+
+ it 'creates the note and interprets the relabel quick action with empty param' do
+ add_note('/relabel')
+
+ wait_for_requests
+ expect(page).not_to have_content '/relabel'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.labels).to match_array([label_bug])
+ end
+
+ context "when current user cannot relabel to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not relabel' do
+ add_note('/relabel ~feature')
+
+ wait_for_requests
+ expect(page).not_to have_content '/relabel'
+ expect(issuable.labels).to match_array([label_bug])
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ before do
+ issuable.update(labels: [label_bug])
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ end
+
+ it 'explains relabel all quick action' do
+ preview_note('/relabel ~feature')
+
+ expect(page).not_to have_content '/relabel'
+ expect(page).to have_content 'Replaces all labels with feature label.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/remove_estimate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/remove_estimate_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..24f6f8d5bf4
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/remove_estimate_quick_action_shared_examples.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+shared_examples 'remove_estimate quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets estimate quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/remove_estimate"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.time_estimate).to eq 0
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ issuable.update_attribute(:time_estimate, 36180)
+ end
+
+ it 'creates the note and interprets the remove_estimate quick action accordingly' do
+ add_note("/remove_estimate")
+
+ wait_for_requests
+ expect(page).not_to have_content '/remove_estimate'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.time_estimate).to eq 0
+ end
+
+ context "when current user cannot remove_estimate" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not remove_estimate' do
+ add_note('/remove_estimate')
+
+ wait_for_requests
+ expect(page).not_to have_content '/remove_estimate'
+ expect(issuable.reload.time_estimate).to eq 36180
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains remove_estimate quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/remove_estimate')
+
+ expect(page).not_to have_content '/remove_estimate'
+ expect(page).to have_content 'Removes time estimate.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/remove_milestone_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/remove_milestone_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..edd92d5cdbc
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/remove_milestone_quick_action_shared_examples.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+shared_examples 'remove_milestone quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets remove_milestone quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/remove_milestone"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.milestone).to be_nil
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ issuable.update(milestone: milestone)
+ expect(issuable.milestone).to eq(milestone)
+ end
+
+ it 'creates the note and interprets the remove_milestone quick action accordingly' do
+ add_note("/remove_milestone")
+
+ wait_for_requests
+ expect(page).not_to have_content '/remove_milestone'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.milestone).to be_nil
+ end
+
+ context "when current user cannot remove milestone to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not remove milestone' do
+ add_note('/remove_milestone')
+
+ wait_for_requests
+ expect(page).not_to have_content '/remove_milestone'
+ expect(issuable.reload.milestone).to eq(milestone)
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains remove_milestone quick action' do
+ issuable.update(milestone: milestone)
+ expect(issuable.milestone).to eq(milestone)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note("/remove_milestone")
+
+ expect(page).not_to have_content '/remove_milestone'
+ expect(page).to have_content 'Removes %ASAP milestone.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/remove_time_spent_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/remove_time_spent_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..6d5894b2318
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/remove_time_spent_quick_action_shared_examples.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+shared_examples 'remove_time_spent quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets remove_time_spent quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/remove_time_spent"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.total_time_spent).to eq 0
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ issuable.update!(spend_time: { duration: 36180, user_id: maintainer.id })
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the remove_time_spent quick action accordingly' do
+ add_note("/remove_time_spent")
+
+ wait_for_requests
+ expect(page).not_to have_content '/remove_time_spent'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.total_time_spent).to eq 0
+ end
+
+ context "when current user cannot set remove_time_spent time" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not set remove_time_spent time' do
+ add_note("/remove_time_spent")
+
+ wait_for_requests
+ expect(page).not_to have_content '/remove_time_spent'
+ expect(issuable.reload.total_time_spent).to eq 36180
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains remove_time_spent quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/remove_time_spent')
+
+ expect(page).not_to have_content '/remove_time_spent'
+ expect(page).to have_content 'Removes spent time.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/reopen_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/reopen_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..af173e93bb5
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/reopen_quick_action_shared_examples.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+shared_examples 'reopen quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets reopen quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/reopen"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ issuable.close
+ expect(issuable).to be_closed
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the reopen quick action accordingly' do
+ add_note('/reopen')
+
+ wait_for_requests
+ expect(page).not_to have_content '/reopen'
+ expect(page).to have_content 'Commands applied'
+
+ issuable.reload
+ expect(issuable).to be_opened
+ end
+
+ context "when current user cannot reopen #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not reopen the #{issuable_type}" do
+ add_note('/reopen')
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(issuable).to be_closed
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains reopen quick action' do
+ issuable.close
+ expect(issuable).to be_closed
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/reopen')
+
+ expect(page).not_to have_content '/reopen'
+ expect(page).to have_content "Reopens this #{issuable_type.to_s.humanize.downcase}."
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/shrug_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/shrug_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..0a526808585
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/shrug_quick_action_shared_examples.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+shared_examples 'shrug quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets shrug quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/shrug oops"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq "bug description\noops ¯\\_(ツ)_/¯"
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content "bug description\noops ¯\\_(ツ)_/¯"
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets shrug quick action accordingly' do
+ add_note("/shrug oops")
+
+ wait_for_requests
+ expect(page).not_to have_content '/shrug oops'
+ expect(page).to have_content "oops ¯\\_(ツ)_/¯"
+ expect(issuable.notes.last.note).to eq "oops ¯\\_(ツ)_/¯"
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains shrug quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/shrug oops')
+
+ expect(page).not_to have_content '/shrug'
+ expect(page).to have_content "oops ¯\\_(ツ)_/¯"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/spend_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/spend_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..97b4885eba0
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/spend_quick_action_shared_examples.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+shared_examples 'spend quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets spend quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/spend 1d 2h 3m"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.total_time_spent).to eq 36180
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the spend quick action accordingly' do
+ add_note("/spend 1d 2h 3m")
+
+ wait_for_requests
+ expect(page).not_to have_content '/spend'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.total_time_spent).to eq 36180
+ end
+
+ context "when current user cannot set spend time" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not set spend time' do
+ add_note("/spend 1s 2h 3m")
+
+ wait_for_requests
+ expect(page).not_to have_content '/spend'
+ expect(issuable.reload.total_time_spent).to eq 0
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains spend quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/spend 1d 2h 3m')
+
+ expect(page).not_to have_content '/spend'
+ expect(page).to have_content 'Adds 1d 2h 3m spent time.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/subscribe_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/subscribe_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..15aefd511a5
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/subscribe_quick_action_shared_examples.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+shared_examples 'subscribe quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets subscribe quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/subscribe"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.subscribed?(maintainer, project)).to be_truthy
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ expect(issuable.subscribed?(maintainer, project)).to be_falsy
+ end
+
+ it 'creates the note and interprets the subscribe quick action accordingly' do
+ add_note('/subscribe')
+
+ wait_for_requests
+ expect(page).not_to have_content '/subscribe'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.subscribed?(maintainer, project)).to be_truthy
+ end
+
+ context "when current user cannot subscribe to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not subscribe to the #{issuable_type}" do
+ add_note('/subscribe')
+
+ wait_for_requests
+ expect(page).not_to have_content '/subscribe'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.subscribed?(maintainer, project)).to be_falsy
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains subscribe quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/subscribe')
+
+ expect(page).not_to have_content '/subscribe'
+ expect(page).to have_content "Subscribes to this #{issuable_type.to_s.humanize.downcase}"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/tableflip_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/tableflip_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..ef831e39872
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/tableflip_quick_action_shared_examples.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+shared_examples 'tableflip quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets tableflip quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/tableflip oops"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq "bug description\noops (╯°□°)╯︵ ┻━┻"
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content "bug description\noops (╯°□°)╯︵ ┻━┻"
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets tableflip quick action accordingly' do
+ add_note("/tableflip oops")
+
+ wait_for_requests
+ expect(page).not_to have_content '/tableflip oops'
+ expect(page).to have_content "oops (╯°□°)╯︵ ┻━┻"
+ expect(issuable.notes.last.note).to eq "oops (╯°□°)╯︵ ┻━┻"
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains tableflip quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/tableflip oops')
+
+ expect(page).not_to have_content '/tableflip'
+ expect(page).to have_content "oops (╯°□°)╯︵ ┻━┻"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..ed904c8d539
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+shared_examples 'issuable time tracker' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ after do
+ wait_for_requests
+ end
+
+ it 'renders the sidebar component empty state' do
+ page.within '.time-tracking-no-tracking-pane' do
+ expect(page).to have_content 'No estimate or time spent'
+ end
+ end
+
+ it 'updates the sidebar component when estimate is added' do
+ submit_time('/estimate 3w 1d 1h')
+
+ wait_for_requests
+ page.within '.time-tracking-estimate-only-pane' do
+ expect(page).to have_content '3w 1d 1h'
+ end
+ end
+
+ it 'updates the sidebar component when spent is added' do
+ submit_time('/spend 3w 1d 1h')
+
+ wait_for_requests
+ page.within '.time-tracking-spend-only-pane' do
+ expect(page).to have_content '3w 1d 1h'
+ end
+ end
+
+ it 'shows the comparison when estimate and spent are added' do
+ submit_time('/estimate 3w 1d 1h')
+ submit_time('/spend 3w 1d 1h')
+
+ wait_for_requests
+ page.within '.time-tracking-comparison-pane' do
+ expect(page).to have_content '3w 1d 1h'
+ end
+ end
+
+ it 'updates the sidebar component when estimate is removed' do
+ submit_time('/estimate 3w 1d 1h')
+ submit_time('/remove_estimate')
+
+ page.within '.time-tracking-component-wrap' do
+ expect(page).to have_content 'No estimate or time spent'
+ end
+ end
+
+ it 'updates the sidebar component when spent is removed' do
+ submit_time('/spend 3w 1d 1h')
+ submit_time('/remove_time_spent')
+
+ page.within '.time-tracking-component-wrap' do
+ expect(page).to have_content 'No estimate or time spent'
+ end
+ end
+
+ it 'shows the help state when icon is clicked' do
+ page.within '.time-tracking-component-wrap' do
+ find('.help-button').click
+ expect(page).to have_content 'Track time with quick actions'
+ expect(page).to have_content 'Learn more'
+ end
+ end
+
+ it 'hides the help state when close icon is clicked' do
+ page.within '.time-tracking-component-wrap' do
+ find('.help-button').click
+ find('.close-help-button').click
+
+ expect(page).not_to have_content 'Track time with quick actions'
+ expect(page).not_to have_content 'Learn more'
+ end
+ end
+
+ it 'displays the correct help url' do
+ page.within '.time-tracking-component-wrap' do
+ find('.help-button').click
+
+ expect(find_link('Learn more')[:href]).to have_content('/help/workflow/time_tracking.md')
+ end
+ end
+end
+
+def submit_time(quick_action)
+ fill_in 'note[note]', with: quick_action
+ find('.js-comment-submit-button').click
+ wait_for_requests
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/title_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/title_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..93a69093dde
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/title_quick_action_shared_examples.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+shared_examples 'title quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets title quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/title new title"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(issuable.title).to eq 'bug 345'
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the title quick action accordingly' do
+ add_note('/title New title')
+
+ wait_for_requests
+ expect(page).not_to have_content '/title new title'
+ expect(page).to have_content 'Commands applied'
+ expect(page).to have_content 'New title'
+
+ issuable.reload
+ expect(issuable.title).to eq 'New title'
+ end
+
+ context "when current user cannot set title #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not set title to the #{issuable_type}" do
+ add_note('/title New title')
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(issuable.title).not_to eq 'New title'
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains title quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/title New title')
+ wait_for_requests
+
+ expect(page).not_to have_content '/title New title'
+ expect(page).to have_content 'Changes the title to "New title".'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/todo_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/todo_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..cccc28127ce
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/todo_quick_action_shared_examples.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+shared_examples 'todo quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets todo quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/todo"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+
+ todos = TodosFinder.new(maintainer).execute
+ expect(todos.size).to eq 0
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the todo quick action accordingly' do
+ add_note('/todo')
+
+ wait_for_requests
+ expect(page).not_to have_content '/todo'
+ expect(page).to have_content 'Commands applied'
+
+ todos = TodosFinder.new(maintainer).execute
+ todo = todos.first
+
+ expect(todos.size).to eq 1
+ expect(todo).to be_pending
+ expect(todo.target).to eq issuable
+ expect(todo.author).to eq maintainer
+ expect(todo.user).to eq maintainer
+ end
+
+ context "when current user cannot add todo #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not add todo the #{issuable_type}" do
+ add_note('/todo')
+
+ expect(page).not_to have_content 'Commands applied'
+ todos = TodosFinder.new(maintainer).execute
+ expect(todos.size).to eq 0
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains todo quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/todo')
+
+ expect(page).not_to have_content '/todo'
+ expect(page).to have_content "Adds a todo."
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/unassign_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unassign_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..0b1a52bc860
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/unassign_quick_action_shared_examples.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+shared_examples 'unassign quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets unassign quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/unassign @bob"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable.assignees).to eq []
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ end
+
+ it "creates the #{issuable_type} and interprets unassign quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/unassign me"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable.assignees).to eq []
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the unassign quick action accordingly' do
+ assignee = create(:user, username: 'bob')
+ issuable.update(assignee_ids: [assignee.id])
+ expect(issuable.assignees).to eq [assignee]
+
+ add_note("Awesome!\n\n/unassign @bob")
+
+ expect(page).to have_content 'Awesome!'
+ expect(page).not_to have_content '/unassign @bob'
+
+ wait_for_requests
+ issuable.reload
+ note = issuable.notes.user.first
+
+ expect(note.note).to eq 'Awesome!'
+ expect(issuable.assignees).to eq []
+ end
+
+ it "unassigns the #{issuable_type} from current user" do
+ issuable.update(assignee_ids: [maintainer.id])
+ expect(issuable.reload.assignees).to eq [maintainer]
+ expect(issuable.assignees).to eq [maintainer]
+
+ add_note("/unassign me")
+
+ expect(page).not_to have_content '/unassign me'
+ expect(page).to have_content 'Commands applied'
+
+ expect(issuable.reload.assignees).to eq []
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains unassign quick action: from bob' do
+ assignee = create(:user, username: 'bob')
+ issuable.update(assignee_ids: [assignee.id])
+ expect(issuable.assignees).to eq [assignee]
+
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ page.within('.js-main-target-form') do
+ fill_in 'note[note]', with: "Awesome!\n/unassign @bob "
+ click_on 'Preview'
+
+ expect(page).not_to have_content '/unassign @bob'
+ expect(page).to have_content 'Awesome!'
+ expect(page).to have_content 'Removes assignee @bob.'
+ end
+ end
+
+ it 'explains unassign quick action: from me' do
+ issuable.update(assignee_ids: [maintainer.id])
+ expect(issuable.assignees).to eq [maintainer]
+
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ page.within('.js-main-target-form') do
+ fill_in 'note[note]', with: "Awesome!\n/unassign me"
+ click_on 'Preview'
+
+ expect(page).not_to have_content '/unassign me'
+ expect(page).to have_content 'Awesome!'
+ expect(page).to have_content "Removes assignee @#{maintainer.username}."
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/unlabel_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unlabel_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..1a1ee05841f
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/unlabel_quick_action_shared_examples.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+
+shared_examples 'unlabel quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets unlabel quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug /unlabel"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.labels).to eq [label_bug]
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ issuable.update(labels: [label_bug, label_feature])
+ end
+
+ it 'creates the note and interprets the unlabel all quick action accordingly' do
+ add_note("/unlabel")
+
+ wait_for_requests
+ expect(page).not_to have_content '/unlabel'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.labels).to eq []
+ end
+
+ it 'creates the note and interprets the unlabel some quick action accordingly' do
+ add_note("/unlabel ~bug")
+
+ wait_for_requests
+ expect(page).not_to have_content '/unlabel'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload.labels).to match_array([label_feature])
+ end
+
+ context "when current user cannot unlabel to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'does not unlabel' do
+ add_note("/unlabel")
+
+ wait_for_requests
+ expect(page).not_to have_content '/unlabel'
+ expect(issuable.labels).to match_array([label_bug, label_feature])
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ before do
+ issuable.update(labels: [label_bug, label_feature])
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ end
+
+ it 'explains unlabel all quick action' do
+ preview_note('/unlabel')
+
+ expect(page).not_to have_content '/unlabel'
+ expect(page).to have_content 'Removes all labels.'
+ end
+
+ it 'explains unlabel some quick action' do
+ preview_note('/unlabel ~bug')
+
+ expect(page).not_to have_content '/unlabel'
+ expect(page).to have_content 'Removes bug label.'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/unlock_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unlock_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..998ff99b32e
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/unlock_quick_action_shared_examples.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+shared_examples 'unlock quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets unlock quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/unlock"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable).not_to be_discussion_locked
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ issuable.update(discussion_locked: true)
+ expect(issuable).to be_discussion_locked
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it 'creates the note and interprets the unlock quick action accordingly' do
+ add_note('/unlock')
+
+ wait_for_requests
+ expect(page).not_to have_content '/unlock'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.reload).not_to be_discussion_locked
+ end
+
+ context "when current user cannot unlock to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not lock the #{issuable_type}" do
+ add_note('/unlock')
+
+ wait_for_requests
+ expect(page).not_to have_content '/unlock'
+ expect(issuable).to be_discussion_locked
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains unlock quick action' do
+ issuable.update(discussion_locked: true)
+ expect(issuable).to be_discussion_locked
+
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+
+ preview_note('/unlock')
+
+ expect(page).not_to have_content '/unlock'
+ expect(page).to have_content 'Unlocks the discussion'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/unsubscribe_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unsubscribe_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..bd92f133889
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issuable/unsubscribe_quick_action_shared_examples.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+shared_examples 'unsubscribe quick action' do |issuable_type|
+ before do
+ project.add_maintainer(maintainer)
+ gitlab_sign_in(maintainer)
+ end
+
+ context "new #{issuable_type}", :js do
+ before do
+ case issuable_type
+ when :merge_request
+ visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ when :issue
+ visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts)
+ wait_for_all_requests
+ end
+ end
+
+ it "creates the #{issuable_type} and interprets unsubscribe quick action accordingly" do
+ fill_in "#{issuable_type}_title", with: 'bug 345'
+ fill_in "#{issuable_type}_description", with: "bug description\n/unsubscribe"
+ click_button "Submit #{issuable_type}".humanize
+
+ issuable = project.public_send(issuable_type.to_s.pluralize).first
+
+ expect(issuable.description).to eq 'bug description'
+ expect(issuable).to be_opened
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content 'bug description'
+ expect(issuable.subscribed?(maintainer, project)).to be_truthy
+ end
+ end
+
+ context "post note to existing #{issuable_type}" do
+ before do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ issuable.subscribe(maintainer, project)
+ expect(issuable.subscribed?(maintainer, project)).to be_truthy
+ end
+
+ it 'creates the note and interprets the unsubscribe quick action accordingly' do
+ add_note('/unsubscribe')
+
+ wait_for_requests
+ expect(page).not_to have_content '/unsubscribe'
+ expect(page).to have_content 'Commands applied'
+ expect(issuable.subscribed?(maintainer, project)).to be_falsey
+ end
+
+ context "when current user cannot unsubscribe to #{issuable_type}" do
+ before do
+ guest = create(:user)
+ project.add_guest(guest)
+
+ gitlab_sign_out
+ gitlab_sign_in(guest)
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ wait_for_all_requests
+ end
+
+ it "does not unsubscribe to the #{issuable_type}" do
+ add_note('/unsubscribe')
+
+ wait_for_requests
+ expect(page).not_to have_content '/unsubscribe'
+ expect(issuable.subscribed?(maintainer, project)).to be_truthy
+ end
+ end
+ end
+
+ context "preview of note on #{issuable_type}", :js do
+ it 'explains unsubscribe quick action' do
+ visit public_send("project_#{issuable_type}_path", project, issuable)
+ issuable.subscribe(maintainer, project)
+ expect(issuable.subscribed?(maintainer, project)).to be_truthy
+
+ preview_note('/unsubscribe')
+
+ expect(page).not_to have_content '/unsubscribe'
+ expect(page).to have_content "Unsubscribes from this #{issuable_type.to_s.humanize.downcase}."
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..6edd20bb024
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'board_move quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/confidential_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/confidential_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..c68e5aee842
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/confidential_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'confidential quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..5bfc3bb222f
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'create_merge_request quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/due_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/due_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..db3ecccc339
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/due_quick_action_shared_examples.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+shared_examples 'due quick action not available' do
+ it 'does not set the due date' do
+ add_note('/due 2016-08-28')
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(page).not_to have_content '/due 2016-08-28'
+ end
+end
+
+shared_examples 'due quick action available and date can be added' do
+ it 'sets the due date accordingly' do
+ add_note('/due 2016-08-28')
+
+ expect(page).not_to have_content '/due 2016-08-28'
+ expect(page).to have_content 'Commands applied'
+
+ visit project_issue_path(project, issue)
+
+ page.within '.due_date' do
+ expect(page).to have_content 'Aug 28, 2016'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..24576fe0021
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'duplicate quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..953e67b0423
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'move quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..5904164fcfc
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+shared_examples 'remove_due_date action not available' do
+ it 'does not remove the due date' do
+ add_note("/remove_due_date")
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(page).not_to have_content '/remove_due_date'
+ end
+end
+
+shared_examples 'remove_due_date action available and due date can be removed' do
+ it 'removes the due date accordingly' do
+ add_note('/remove_due_date')
+
+ expect(page).not_to have_content '/remove_due_date'
+ expect(page).to have_content 'Commands applied'
+
+ visit project_issue_path(project, issue)
+
+ page.within '.due_date' do
+ expect(page).to have_content 'No due date'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..31d88183f0d
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'merge quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/merge_request/target_branch_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/target_branch_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..ccb4a85325b
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/merge_request/target_branch_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'target_branch quick action' do
+end
diff --git a/spec/support/shared_examples/quick_actions/merge_request/wip_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/wip_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..6abb12b41b2
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/merge_request/wip_quick_action_shared_examples.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+shared_examples 'wip quick action' do
+end
diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb
index 533e9d87ea6..9ce9a353913 100644
--- a/spec/uploaders/object_storage_spec.rb
+++ b/spec/uploaders/object_storage_spec.rb
@@ -375,7 +375,7 @@ describe ObjectStorage do
describe '#fog_public' do
subject { uploader.fog_public }
- it { is_expected.to eq(false) }
+ it { is_expected.to eq(nil) }
end
describe '.workhorse_authorize' do
diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index 2c60ccfb754..c6c10001bc5 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -113,4 +113,56 @@ describe 'layouts/nav/sidebar/_project' do
end
end
end
+
+ describe 'ci/cd settings tab' do
+ before do
+ project.update!(archived: project_archived)
+ end
+
+ context 'when project is archived' do
+ let(:project_archived) { true }
+
+ it 'does not show the ci/cd settings tab' do
+ render
+
+ expect(rendered).not_to have_link('CI / CD', href: project_settings_ci_cd_path(project))
+ end
+ end
+
+ context 'when project is active' do
+ let(:project_archived) { false }
+
+ it 'shows the ci/cd settings tab' do
+ render
+
+ expect(rendered).to have_link('CI / CD', href: project_settings_ci_cd_path(project))
+ end
+ end
+ end
+
+ describe 'operations settings tab' do
+ before do
+ project.update!(archived: project_archived)
+ end
+
+ context 'when project is archived' do
+ let(:project_archived) { true }
+
+ it 'does not show the operations settings tab' do
+ render
+
+ expect(rendered).not_to have_link('Operations', href: project_settings_operations_path(project))
+ end
+ end
+
+ context 'when project is active' do
+ let(:project_archived) { false }
+
+ it 'shows the operations settings tab' do
+ render
+
+ expect(rendered).to have_link('Operations', href: project_settings_operations_path(project))
+ end
+ end
+ end
end
diff --git a/spec/workers/admin_email_worker_spec.rb b/spec/workers/admin_email_worker_spec.rb
index 27687f069ea..f72b932423f 100644
--- a/spec/workers/admin_email_worker_spec.rb
+++ b/spec/workers/admin_email_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe AdminEmailWorker do
diff --git a/spec/workers/archive_trace_worker_spec.rb b/spec/workers/archive_trace_worker_spec.rb
index 7244ad4f199..368ed3f3db1 100644
--- a/spec/workers/archive_trace_worker_spec.rb
+++ b/spec/workers/archive_trace_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ArchiveTraceWorker do
diff --git a/spec/workers/authorized_projects_worker_spec.rb b/spec/workers/authorized_projects_worker_spec.rb
index d095138f6b7..4c02278de64 100644
--- a/spec/workers/authorized_projects_worker_spec.rb
+++ b/spec/workers/authorized_projects_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe AuthorizedProjectsWorker do
diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb
index 3bd072e7125..746c858609f 100644
--- a/spec/workers/background_migration_worker_spec.rb
+++ b/spec/workers/background_migration_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BackgroundMigrationWorker, :sidekiq, :clean_gitlab_redis_shared_state do
diff --git a/spec/workers/build_coverage_worker_spec.rb b/spec/workers/build_coverage_worker_spec.rb
index ba20488f663..25686ae68ca 100644
--- a/spec/workers/build_coverage_worker_spec.rb
+++ b/spec/workers/build_coverage_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BuildCoverageWorker do
diff --git a/spec/workers/build_finished_worker_spec.rb b/spec/workers/build_finished_worker_spec.rb
index ccb26849e67..33f327d4a0c 100644
--- a/spec/workers/build_finished_worker_spec.rb
+++ b/spec/workers/build_finished_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BuildFinishedWorker do
diff --git a/spec/workers/build_hooks_worker_spec.rb b/spec/workers/build_hooks_worker_spec.rb
index 97654a93f5c..59b252a8be3 100644
--- a/spec/workers/build_hooks_worker_spec.rb
+++ b/spec/workers/build_hooks_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BuildHooksWorker do
diff --git a/spec/workers/build_success_worker_spec.rb b/spec/workers/build_success_worker_spec.rb
index 5eb9709ded9..065aeaf2b65 100644
--- a/spec/workers/build_success_worker_spec.rb
+++ b/spec/workers/build_success_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BuildSuccessWorker do
diff --git a/spec/workers/build_trace_sections_worker_spec.rb b/spec/workers/build_trace_sections_worker_spec.rb
index 45243f45547..97fc0a2da0c 100644
--- a/spec/workers/build_trace_sections_worker_spec.rb
+++ b/spec/workers/build_trace_sections_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe BuildTraceSectionsWorker do
diff --git a/spec/workers/ci/archive_traces_cron_worker_spec.rb b/spec/workers/ci/archive_traces_cron_worker_spec.rb
index 478fb7d2c0f..eca6cf5235f 100644
--- a/spec/workers/ci/archive_traces_cron_worker_spec.rb
+++ b/spec/workers/ci/archive_traces_cron_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::ArchiveTracesCronWorker do
diff --git a/spec/workers/ci/build_schedule_worker_spec.rb b/spec/workers/ci/build_schedule_worker_spec.rb
index 4a3fe84d7f7..647f9763fed 100644
--- a/spec/workers/ci/build_schedule_worker_spec.rb
+++ b/spec/workers/ci/build_schedule_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Ci::BuildScheduleWorker do
diff --git a/spec/workers/cluster_provision_worker_spec.rb b/spec/workers/cluster_provision_worker_spec.rb
index da32f29fec0..9cc2ad12bfc 100644
--- a/spec/workers/cluster_provision_worker_spec.rb
+++ b/spec/workers/cluster_provision_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ClusterProvisionWorker do
diff --git a/spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb b/spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb
index 2e2e9afd25a..a9ffdfb085e 100644
--- a/spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb
+++ b/spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ClusterWaitForIngressIpAddressWorker do
diff --git a/spec/workers/concerns/application_worker_spec.rb b/spec/workers/concerns/application_worker_spec.rb
index 901d77178bc..ae5244e2f62 100644
--- a/spec/workers/concerns/application_worker_spec.rb
+++ b/spec/workers/concerns/application_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ApplicationWorker do
diff --git a/spec/workers/concerns/cluster_queue_spec.rb b/spec/workers/concerns/cluster_queue_spec.rb
index 4118b9aa194..732d55dfbde 100644
--- a/spec/workers/concerns/cluster_queue_spec.rb
+++ b/spec/workers/concerns/cluster_queue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ClusterQueue do
diff --git a/spec/workers/concerns/cronjob_queue_spec.rb b/spec/workers/concerns/cronjob_queue_spec.rb
index c042a52f41f..cf4d47b7500 100644
--- a/spec/workers/concerns/cronjob_queue_spec.rb
+++ b/spec/workers/concerns/cronjob_queue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CronjobQueue do
diff --git a/spec/workers/concerns/gitlab/github_import/notify_upon_death_spec.rb b/spec/workers/concerns/gitlab/github_import/notify_upon_death_spec.rb
index 4b9aa9a7ef8..200cdffd560 100644
--- a/spec/workers/concerns/gitlab/github_import/notify_upon_death_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/notify_upon_death_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::NotifyUponDeath do
diff --git a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
index 9c187bead0a..51b685b5792 100644
--- a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::ObjectImporter do
diff --git a/spec/workers/concerns/gitlab/github_import/queue_spec.rb b/spec/workers/concerns/gitlab/github_import/queue_spec.rb
index a96f583aff7..d262bc2e05c 100644
--- a/spec/workers/concerns/gitlab/github_import/queue_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/queue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Queue do
diff --git a/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb b/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
index 8de4059c4ae..294eacf09ab 100644
--- a/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::ReschedulingMethods do
diff --git a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
index d85a87f2cb0..f9081a875b5 100644
--- a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::StageMethods do
diff --git a/spec/workers/concerns/pipeline_background_queue_spec.rb b/spec/workers/concerns/pipeline_background_queue_spec.rb
index 24c0a3c6a20..78ceafb359f 100644
--- a/spec/workers/concerns/pipeline_background_queue_spec.rb
+++ b/spec/workers/concerns/pipeline_background_queue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineBackgroundQueue do
diff --git a/spec/workers/concerns/pipeline_queue_spec.rb b/spec/workers/concerns/pipeline_queue_spec.rb
index a312b307fce..eedfceb8bf0 100644
--- a/spec/workers/concerns/pipeline_queue_spec.rb
+++ b/spec/workers/concerns/pipeline_queue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineQueue do
diff --git a/spec/workers/concerns/project_import_options_spec.rb b/spec/workers/concerns/project_import_options_spec.rb
index 3699fd83a9a..c5fbcfb5fb0 100644
--- a/spec/workers/concerns/project_import_options_spec.rb
+++ b/spec/workers/concerns/project_import_options_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectImportOptions do
diff --git a/spec/workers/concerns/repository_check_queue_spec.rb b/spec/workers/concerns/repository_check_queue_spec.rb
index d2eeecfc9a8..55ed71f124c 100644
--- a/spec/workers/concerns/repository_check_queue_spec.rb
+++ b/spec/workers/concerns/repository_check_queue_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryCheckQueue do
diff --git a/spec/workers/concerns/waitable_worker_spec.rb b/spec/workers/concerns/waitable_worker_spec.rb
index ce38cde9208..37fadd6ac02 100644
--- a/spec/workers/concerns/waitable_worker_spec.rb
+++ b/spec/workers/concerns/waitable_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe WaitableWorker do
diff --git a/spec/workers/create_gpg_signature_worker_spec.rb b/spec/workers/create_gpg_signature_worker_spec.rb
index f5479e57260..ae09b4b77f1 100644
--- a/spec/workers/create_gpg_signature_worker_spec.rb
+++ b/spec/workers/create_gpg_signature_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CreateGpgSignatureWorker do
diff --git a/spec/workers/create_note_diff_file_worker_spec.rb b/spec/workers/create_note_diff_file_worker_spec.rb
index 0ac946a1232..e35aaa7d593 100644
--- a/spec/workers/create_note_diff_file_worker_spec.rb
+++ b/spec/workers/create_note_diff_file_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CreateNoteDiffFileWorker do
diff --git a/spec/workers/create_pipeline_worker_spec.rb b/spec/workers/create_pipeline_worker_spec.rb
index 02cb0f46cb4..62a17da80c0 100644
--- a/spec/workers/create_pipeline_worker_spec.rb
+++ b/spec/workers/create_pipeline_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe CreatePipelineWorker do
diff --git a/spec/workers/delete_diff_files_worker_spec.rb b/spec/workers/delete_diff_files_worker_spec.rb
index e0edd313922..9f8b20df48e 100644
--- a/spec/workers/delete_diff_files_worker_spec.rb
+++ b/spec/workers/delete_diff_files_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DeleteDiffFilesWorker do
diff --git a/spec/workers/delete_merged_branches_worker_spec.rb b/spec/workers/delete_merged_branches_worker_spec.rb
index 39009d9e4b2..a218ca921d9 100644
--- a/spec/workers/delete_merged_branches_worker_spec.rb
+++ b/spec/workers/delete_merged_branches_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DeleteMergedBranchesWorker do
diff --git a/spec/workers/delete_user_worker_spec.rb b/spec/workers/delete_user_worker_spec.rb
index 06d9e125105..c963b886e62 100644
--- a/spec/workers/delete_user_worker_spec.rb
+++ b/spec/workers/delete_user_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DeleteUserWorker do
diff --git a/spec/workers/deployments/success_worker_spec.rb b/spec/workers/deployments/success_worker_spec.rb
index ba7d45eca01..1c68922b03d 100644
--- a/spec/workers/deployments/success_worker_spec.rb
+++ b/spec/workers/deployments/success_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Deployments::SuccessWorker do
diff --git a/spec/workers/detect_repository_languages_worker_spec.rb b/spec/workers/detect_repository_languages_worker_spec.rb
index ff3878fbc8e..dbf32555985 100644
--- a/spec/workers/detect_repository_languages_worker_spec.rb
+++ b/spec/workers/detect_repository_languages_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe DetectRepositoryLanguagesWorker do
diff --git a/spec/workers/email_receiver_worker_spec.rb b/spec/workers/email_receiver_worker_spec.rb
index 045135255d6..f8a31fcdee6 100644
--- a/spec/workers/email_receiver_worker_spec.rb
+++ b/spec/workers/email_receiver_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe EmailReceiverWorker, :mailer do
diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb
index 05b4fb49ea3..0f87df89c29 100644
--- a/spec/workers/emails_on_push_worker_spec.rb
+++ b/spec/workers/emails_on_push_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe EmailsOnPushWorker, :mailer do
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index ebe02373275..8fddd8540ef 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'Every Sidekiq worker' do
diff --git a/spec/workers/expire_build_artifacts_worker_spec.rb b/spec/workers/expire_build_artifacts_worker_spec.rb
index 27995cf1611..74d6b5605d1 100644
--- a/spec/workers/expire_build_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_artifacts_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ExpireBuildArtifactsWorker do
diff --git a/spec/workers/expire_build_instance_artifacts_worker_spec.rb b/spec/workers/expire_build_instance_artifacts_worker_spec.rb
index e1a56c72162..bdb5a3801d9 100644
--- a/spec/workers/expire_build_instance_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_instance_artifacts_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ExpireBuildInstanceArtifactsWorker do
diff --git a/spec/workers/expire_job_cache_worker_spec.rb b/spec/workers/expire_job_cache_worker_spec.rb
index 1b614342a18..6ac285ca944 100644
--- a/spec/workers/expire_job_cache_worker_spec.rb
+++ b/spec/workers/expire_job_cache_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ExpireJobCacheWorker do
diff --git a/spec/workers/expire_pipeline_cache_worker_spec.rb b/spec/workers/expire_pipeline_cache_worker_spec.rb
index 54c9a69d329..c98b69ef76c 100644
--- a/spec/workers/expire_pipeline_cache_worker_spec.rb
+++ b/spec/workers/expire_pipeline_cache_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ExpirePipelineCacheWorker do
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 4895a968d6e..2459638c3e6 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'fileutils'
require 'spec_helper'
diff --git a/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
index fc7aafbc0c9..b1647d8c7df 100644
--- a/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::AdvanceStageWorker, :clean_gitlab_redis_shared_state do
diff --git a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
index 5b1c6b6010a..42d69ff6166 100644
--- a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::ImportDiffNoteWorker do
diff --git a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
index ab070d6d081..06a573e16b7 100644
--- a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::ImportIssueWorker do
diff --git a/spec/workers/gitlab/github_import/import_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
index 3a30f06bb2d..5110c3ff11b 100644
--- a/spec/workers/gitlab/github_import/import_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::ImportNoteWorker do
diff --git a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
index 3cccd7cab21..d46e381fc51 100644
--- a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::ImportPullRequestWorker do
diff --git a/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb b/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb
index 7ff133f1049..fa4ded8e42f 100644
--- a/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::RefreshImportJidWorker do
diff --git a/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb b/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb
index 91e0cddb5d8..35a856802c2 100644
--- a/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Stage::FinishImportWorker do
diff --git a/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb
index ad6154cc4a4..0c7fc2a164e 100644
--- a/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Stage::ImportBaseDataWorker do
diff --git a/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
index ab347f5b75b..5d96f562c30 100644
--- a/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Stage::ImportIssuesAndDiffNotesWorker do
diff --git a/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb
index b19884d7991..e7c9dabb292 100644
--- a/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Stage::ImportLfsObjectsWorker do
diff --git a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
index 94cff9e4e80..90590a45900 100644
--- a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Stage::ImportNotesWorker do
diff --git a/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb
index 1fbb073a34a..15d485f1018 100644
--- a/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Stage::ImportPullRequestsWorker do
diff --git a/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
index adab535ac05..6d47d73b92e 100644
--- a/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
diff --git a/spec/workers/gitlab_shell_worker_spec.rb b/spec/workers/gitlab_shell_worker_spec.rb
index 6b222af454d..0758cfc4ee2 100644
--- a/spec/workers/gitlab_shell_worker_spec.rb
+++ b/spec/workers/gitlab_shell_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GitlabShellWorker do
diff --git a/spec/workers/gitlab_usage_ping_worker_spec.rb b/spec/workers/gitlab_usage_ping_worker_spec.rb
index 49b4e04dc7c..aff5d112cdd 100644
--- a/spec/workers/gitlab_usage_ping_worker_spec.rb
+++ b/spec/workers/gitlab_usage_ping_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GitlabUsagePingWorker do
diff --git a/spec/workers/group_destroy_worker_spec.rb b/spec/workers/group_destroy_worker_spec.rb
index a170c84ab12..90a4150a31a 100644
--- a/spec/workers/group_destroy_worker_spec.rb
+++ b/spec/workers/group_destroy_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe GroupDestroyWorker do
diff --git a/spec/workers/hashed_storage/migrator_worker_spec.rb b/spec/workers/hashed_storage/migrator_worker_spec.rb
index a85f820a3eb..a318cdd003e 100644
--- a/spec/workers/hashed_storage/migrator_worker_spec.rb
+++ b/spec/workers/hashed_storage/migrator_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe HashedStorage::MigratorWorker do
diff --git a/spec/workers/hashed_storage/project_migrate_worker_spec.rb b/spec/workers/hashed_storage/project_migrate_worker_spec.rb
index 340e722aa7e..f266c7dbe8c 100644
--- a/spec/workers/hashed_storage/project_migrate_worker_spec.rb
+++ b/spec/workers/hashed_storage/project_migrate_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe HashedStorage::ProjectMigrateWorker, :clean_gitlab_redis_shared_state do
diff --git a/spec/workers/invalid_gpg_signature_update_worker_spec.rb b/spec/workers/invalid_gpg_signature_update_worker_spec.rb
index 5972696515b..4f727469ea8 100644
--- a/spec/workers/invalid_gpg_signature_update_worker_spec.rb
+++ b/spec/workers/invalid_gpg_signature_update_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe InvalidGpgSignatureUpdateWorker do
diff --git a/spec/workers/issue_due_scheduler_worker_spec.rb b/spec/workers/issue_due_scheduler_worker_spec.rb
index 2710267d384..61ad8330840 100644
--- a/spec/workers/issue_due_scheduler_worker_spec.rb
+++ b/spec/workers/issue_due_scheduler_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe IssueDueSchedulerWorker do
diff --git a/spec/workers/mail_scheduler/issue_due_worker_spec.rb b/spec/workers/mail_scheduler/issue_due_worker_spec.rb
index 1026ae5b4bf..fa17775e9f2 100644
--- a/spec/workers/mail_scheduler/issue_due_worker_spec.rb
+++ b/spec/workers/mail_scheduler/issue_due_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MailScheduler::IssueDueWorker do
diff --git a/spec/workers/mail_scheduler/notification_service_worker_spec.rb b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
index 5cfba01850c..0729c5f9ffb 100644
--- a/spec/workers/mail_scheduler/notification_service_worker_spec.rb
+++ b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MailScheduler::NotificationServiceWorker do
diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb
index b57c275c770..138a99abde6 100644
--- a/spec/workers/merge_worker_spec.rb
+++ b/spec/workers/merge_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe MergeWorker do
diff --git a/spec/workers/namespaceless_project_destroy_worker_spec.rb b/spec/workers/namespaceless_project_destroy_worker_spec.rb
index 2f21a1321e1..4fbda37e268 100644
--- a/spec/workers/namespaceless_project_destroy_worker_spec.rb
+++ b/spec/workers/namespaceless_project_destroy_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe NamespacelessProjectDestroyWorker do
diff --git a/spec/workers/new_issue_worker_spec.rb b/spec/workers/new_issue_worker_spec.rb
index baa8ddb59e5..88a75ce5b70 100644
--- a/spec/workers/new_issue_worker_spec.rb
+++ b/spec/workers/new_issue_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe NewIssueWorker do
diff --git a/spec/workers/new_merge_request_worker_spec.rb b/spec/workers/new_merge_request_worker_spec.rb
index c3f29a40d58..d078ddd07d9 100644
--- a/spec/workers/new_merge_request_worker_spec.rb
+++ b/spec/workers/new_merge_request_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe NewMergeRequestWorker do
diff --git a/spec/workers/new_note_worker_spec.rb b/spec/workers/new_note_worker_spec.rb
index 575361c93d4..2966a201a62 100644
--- a/spec/workers/new_note_worker_spec.rb
+++ b/spec/workers/new_note_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe NewNoteWorker do
diff --git a/spec/workers/pages_domain_verification_cron_worker_spec.rb b/spec/workers/pages_domain_verification_cron_worker_spec.rb
index 8f780428c82..9b479da1cb6 100644
--- a/spec/workers/pages_domain_verification_cron_worker_spec.rb
+++ b/spec/workers/pages_domain_verification_cron_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PagesDomainVerificationCronWorker do
diff --git a/spec/workers/pages_domain_verification_worker_spec.rb b/spec/workers/pages_domain_verification_worker_spec.rb
index 372fc95ab4a..2f23dcb487f 100644
--- a/spec/workers/pages_domain_verification_worker_spec.rb
+++ b/spec/workers/pages_domain_verification_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PagesDomainVerificationWorker do
diff --git a/spec/workers/pipeline_hooks_worker_spec.rb b/spec/workers/pipeline_hooks_worker_spec.rb
index 035e329839f..60df08f40da 100644
--- a/spec/workers/pipeline_hooks_worker_spec.rb
+++ b/spec/workers/pipeline_hooks_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineHooksWorker do
diff --git a/spec/workers/pipeline_metrics_worker_spec.rb b/spec/workers/pipeline_metrics_worker_spec.rb
index 896f9e6e7f2..6beecbcd114 100644
--- a/spec/workers/pipeline_metrics_worker_spec.rb
+++ b/spec/workers/pipeline_metrics_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineMetricsWorker do
diff --git a/spec/workers/pipeline_notification_worker_spec.rb b/spec/workers/pipeline_notification_worker_spec.rb
index eb539ffd893..98b0f139fe2 100644
--- a/spec/workers/pipeline_notification_worker_spec.rb
+++ b/spec/workers/pipeline_notification_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineNotificationWorker, :mailer do
diff --git a/spec/workers/pipeline_process_worker_spec.rb b/spec/workers/pipeline_process_worker_spec.rb
index 86e9d7f6684..d33cf72e51e 100644
--- a/spec/workers/pipeline_process_worker_spec.rb
+++ b/spec/workers/pipeline_process_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineProcessWorker do
diff --git a/spec/workers/pipeline_schedule_worker_spec.rb b/spec/workers/pipeline_schedule_worker_spec.rb
index ff408427926..f23910d23be 100644
--- a/spec/workers/pipeline_schedule_worker_spec.rb
+++ b/spec/workers/pipeline_schedule_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineScheduleWorker do
diff --git a/spec/workers/pipeline_success_worker_spec.rb b/spec/workers/pipeline_success_worker_spec.rb
index d1c84adda6f..4cbe384b47a 100644
--- a/spec/workers/pipeline_success_worker_spec.rb
+++ b/spec/workers/pipeline_success_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineSuccessWorker do
diff --git a/spec/workers/pipeline_update_worker_spec.rb b/spec/workers/pipeline_update_worker_spec.rb
index 0b456cfd0da..0225e4a9601 100644
--- a/spec/workers/pipeline_update_worker_spec.rb
+++ b/spec/workers/pipeline_update_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PipelineUpdateWorker do
diff --git a/spec/workers/plugin_worker_spec.rb b/spec/workers/plugin_worker_spec.rb
index 9238a8199bc..ca6c9986131 100644
--- a/spec/workers/plugin_worker_spec.rb
+++ b/spec/workers/plugin_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PluginWorker do
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 9cddad71a51..66958a4c116 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PostReceive do
diff --git a/spec/workers/process_commit_worker_spec.rb b/spec/workers/process_commit_worker_spec.rb
index 2d071c181c2..47bac63511e 100644
--- a/spec/workers/process_commit_worker_spec.rb
+++ b/spec/workers/process_commit_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProcessCommitWorker do
diff --git a/spec/workers/project_cache_worker_spec.rb b/spec/workers/project_cache_worker_spec.rb
index b9b5445562f..a7353227043 100644
--- a/spec/workers/project_cache_worker_spec.rb
+++ b/spec/workers/project_cache_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectCacheWorker do
diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb
index 6132f145f8d..ec40900a5b7 100644
--- a/spec/workers/project_destroy_worker_spec.rb
+++ b/spec/workers/project_destroy_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectDestroyWorker do
diff --git a/spec/workers/project_export_worker_spec.rb b/spec/workers/project_export_worker_spec.rb
index 8899969c178..8065087796c 100644
--- a/spec/workers/project_export_worker_spec.rb
+++ b/spec/workers/project_export_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ProjectExportWorker do
diff --git a/spec/workers/propagate_service_template_worker_spec.rb b/spec/workers/propagate_service_template_worker_spec.rb
index af1fb80a51d..fb4ced77832 100644
--- a/spec/workers/propagate_service_template_worker_spec.rb
+++ b/spec/workers/propagate_service_template_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PropagateServiceTemplateWorker do
diff --git a/spec/workers/prune_old_events_worker_spec.rb b/spec/workers/prune_old_events_worker_spec.rb
index ea2b6ae229e..f1eef1923bf 100644
--- a/spec/workers/prune_old_events_worker_spec.rb
+++ b/spec/workers/prune_old_events_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PruneOldEventsWorker do
diff --git a/spec/workers/prune_web_hook_logs_worker_spec.rb b/spec/workers/prune_web_hook_logs_worker_spec.rb
index b3ec71d4a00..e57334967fd 100644
--- a/spec/workers/prune_web_hook_logs_worker_spec.rb
+++ b/spec/workers/prune_web_hook_logs_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe PruneWebHookLogsWorker do
diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb
index 3da851de067..2395e6ec947 100644
--- a/spec/workers/reactive_caching_worker_spec.rb
+++ b/spec/workers/reactive_caching_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe ReactiveCachingWorker do
diff --git a/spec/workers/rebase_worker_spec.rb b/spec/workers/rebase_worker_spec.rb
index 900332ed6b3..578b8cf7451 100644
--- a/spec/workers/rebase_worker_spec.rb
+++ b/spec/workers/rebase_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RebaseWorker, '#perform' do
diff --git a/spec/workers/remote_mirror_notification_worker_spec.rb b/spec/workers/remote_mirror_notification_worker_spec.rb
index e3db10ed645..5182f67b4af 100644
--- a/spec/workers/remote_mirror_notification_worker_spec.rb
+++ b/spec/workers/remote_mirror_notification_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RemoteMirrorNotificationWorker, :mailer do
diff --git a/spec/workers/remove_expired_group_links_worker_spec.rb b/spec/workers/remove_expired_group_links_worker_spec.rb
index 689bc3d27b4..10d9aa37dee 100644
--- a/spec/workers/remove_expired_group_links_worker_spec.rb
+++ b/spec/workers/remove_expired_group_links_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RemoveExpiredGroupLinksWorker do
diff --git a/spec/workers/remove_expired_members_worker_spec.rb b/spec/workers/remove_expired_members_worker_spec.rb
index 058fdf4c009..69a5725bb35 100644
--- a/spec/workers/remove_expired_members_worker_spec.rb
+++ b/spec/workers/remove_expired_members_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RemoveExpiredMembersWorker do
diff --git a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
index 57f83c1dbe9..0e21933a9a5 100644
--- a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
+++ b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RemoveUnreferencedLfsObjectsWorker do
diff --git a/spec/workers/repository_check/batch_worker_spec.rb b/spec/workers/repository_check/batch_worker_spec.rb
index 50b93fce2dc..051c6a5d141 100644
--- a/spec/workers/repository_check/batch_worker_spec.rb
+++ b/spec/workers/repository_check/batch_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryCheck::BatchWorker do
diff --git a/spec/workers/repository_check/clear_worker_spec.rb b/spec/workers/repository_check/clear_worker_spec.rb
index 1c49415d46c..7ad9e287204 100644
--- a/spec/workers/repository_check/clear_worker_spec.rb
+++ b/spec/workers/repository_check/clear_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryCheck::ClearWorker do
diff --git a/spec/workers/repository_check/dispatch_worker_spec.rb b/spec/workers/repository_check/dispatch_worker_spec.rb
index 7877429aa8f..03efb6a0a80 100644
--- a/spec/workers/repository_check/dispatch_worker_spec.rb
+++ b/spec/workers/repository_check/dispatch_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryCheck::DispatchWorker do
diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb
index f11875cffd1..65e1c5e9d5d 100644
--- a/spec/workers/repository_check/single_repository_worker_spec.rb
+++ b/spec/workers/repository_check/single_repository_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
require 'fileutils'
diff --git a/spec/workers/repository_cleanup_worker_spec.rb b/spec/workers/repository_cleanup_worker_spec.rb
index 3adae0b6cfa..e58664cf22a 100644
--- a/spec/workers/repository_cleanup_worker_spec.rb
+++ b/spec/workers/repository_cleanup_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryCleanupWorker do
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 31bfe88d0bd..26fd67adfaa 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryForkWorker do
diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb
index 87ac4bc05c1..b8767af8eee 100644
--- a/spec/workers/repository_import_worker_spec.rb
+++ b/spec/workers/repository_import_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RepositoryImportWorker do
diff --git a/spec/workers/repository_remove_remote_worker_spec.rb b/spec/workers/repository_remove_remote_worker_spec.rb
index 6ddb653d142..6eba5c50960 100644
--- a/spec/workers/repository_remove_remote_worker_spec.rb
+++ b/spec/workers/repository_remove_remote_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe RepositoryRemoveRemoteWorker do
diff --git a/spec/workers/repository_update_remote_mirror_worker_spec.rb b/spec/workers/repository_update_remote_mirror_worker_spec.rb
index b582a3650b6..4de51ecb3e9 100644
--- a/spec/workers/repository_update_remote_mirror_worker_spec.rb
+++ b/spec/workers/repository_update_remote_mirror_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe RepositoryUpdateRemoteMirrorWorker do
diff --git a/spec/workers/run_pipeline_schedule_worker_spec.rb b/spec/workers/run_pipeline_schedule_worker_spec.rb
index 481a84837f9..690af22f4dc 100644
--- a/spec/workers/run_pipeline_schedule_worker_spec.rb
+++ b/spec/workers/run_pipeline_schedule_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe RunPipelineScheduleWorker do
diff --git a/spec/workers/stage_update_worker_spec.rb b/spec/workers/stage_update_worker_spec.rb
index 7bc76c79464..429d42bac29 100644
--- a/spec/workers/stage_update_worker_spec.rb
+++ b/spec/workers/stage_update_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe StageUpdateWorker do
diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb
index e09b8e5b964..72de62f1188 100644
--- a/spec/workers/stuck_ci_jobs_worker_spec.rb
+++ b/spec/workers/stuck_ci_jobs_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe StuckCiJobsWorker do
diff --git a/spec/workers/stuck_import_jobs_worker_spec.rb b/spec/workers/stuck_import_jobs_worker_spec.rb
index e94d2be9850..dcb8e59ed28 100644
--- a/spec/workers/stuck_import_jobs_worker_spec.rb
+++ b/spec/workers/stuck_import_jobs_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe StuckImportJobsWorker do
diff --git a/spec/workers/stuck_merge_jobs_worker_spec.rb b/spec/workers/stuck_merge_jobs_worker_spec.rb
index 5aaff27a6b2..09efed6d2cf 100644
--- a/spec/workers/stuck_merge_jobs_worker_spec.rb
+++ b/spec/workers/stuck_merge_jobs_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe StuckMergeJobsWorker do
diff --git a/spec/workers/system_hook_push_worker_spec.rb b/spec/workers/system_hook_push_worker_spec.rb
index b1d446ed25f..890a622d11a 100644
--- a/spec/workers/system_hook_push_worker_spec.rb
+++ b/spec/workers/system_hook_push_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe SystemHookPushWorker do
diff --git a/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb b/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb
index 9d7c0b8f560..18876b71615 100644
--- a/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb
+++ b/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TodosDestroyer::ConfidentialIssueWorker do
diff --git a/spec/workers/todos_destroyer/entity_leave_worker_spec.rb b/spec/workers/todos_destroyer/entity_leave_worker_spec.rb
index 955447906aa..cb14fac0910 100644
--- a/spec/workers/todos_destroyer/entity_leave_worker_spec.rb
+++ b/spec/workers/todos_destroyer/entity_leave_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TodosDestroyer::EntityLeaveWorker do
diff --git a/spec/workers/todos_destroyer/group_private_worker_spec.rb b/spec/workers/todos_destroyer/group_private_worker_spec.rb
index fcc38989ced..d9a240136d5 100644
--- a/spec/workers/todos_destroyer/group_private_worker_spec.rb
+++ b/spec/workers/todos_destroyer/group_private_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TodosDestroyer::GroupPrivateWorker do
diff --git a/spec/workers/todos_destroyer/private_features_worker_spec.rb b/spec/workers/todos_destroyer/private_features_worker_spec.rb
index 9599f5ee071..abd04acc3bd 100644
--- a/spec/workers/todos_destroyer/private_features_worker_spec.rb
+++ b/spec/workers/todos_destroyer/private_features_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TodosDestroyer::PrivateFeaturesWorker do
diff --git a/spec/workers/todos_destroyer/project_private_worker_spec.rb b/spec/workers/todos_destroyer/project_private_worker_spec.rb
index 15d926fa9d5..c1bb0438ec3 100644
--- a/spec/workers/todos_destroyer/project_private_worker_spec.rb
+++ b/spec/workers/todos_destroyer/project_private_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TodosDestroyer::ProjectPrivateWorker do
diff --git a/spec/workers/trending_projects_worker_spec.rb b/spec/workers/trending_projects_worker_spec.rb
index c3c6fdcf2d5..6e524085662 100644
--- a/spec/workers/trending_projects_worker_spec.rb
+++ b/spec/workers/trending_projects_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe TrendingProjectsWorker do
diff --git a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
index d20d926f5a0..c4af829a5e2 100644
--- a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
+++ b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe UpdateHeadPipelineForMergeRequestWorker do
diff --git a/spec/workers/update_merge_requests_worker_spec.rb b/spec/workers/update_merge_requests_worker_spec.rb
index 0b553db0ca4..486dade454a 100644
--- a/spec/workers/update_merge_requests_worker_spec.rb
+++ b/spec/workers/update_merge_requests_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe UpdateMergeRequestsWorker do
diff --git a/spec/workers/upload_checksum_worker_spec.rb b/spec/workers/upload_checksum_worker_spec.rb
index 9e50ce15871..7202c8001b4 100644
--- a/spec/workers/upload_checksum_worker_spec.rb
+++ b/spec/workers/upload_checksum_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rails_helper'
describe UploadChecksumWorker do
diff --git a/spec/workers/wait_for_cluster_creation_worker_spec.rb b/spec/workers/wait_for_cluster_creation_worker_spec.rb
index 0e92b298178..850eba263a7 100644
--- a/spec/workers/wait_for_cluster_creation_worker_spec.rb
+++ b/spec/workers/wait_for_cluster_creation_worker_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe WaitForClusterCreationWorker do
diff --git a/yarn.lock b/yarn.lock
index 2bdbca103b1..846e29862f1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -658,10 +658,10 @@
eslint-plugin-promise "^4.0.1"
eslint-plugin-vue "^5.0.0"
-"@gitlab/svgs@^1.54.0":
- version "1.54.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.54.0.tgz#00320e845efd46716042cde0c348b990d4908daf"
- integrity sha512-DR17iy8TM5IbXEacqiDP0p8SuC/J8EL+98xbfVz5BKvRsPHpeZJQNlBF/petIV5d+KWM5A9v3GZTY7uMU7z/JQ==
+"@gitlab/svgs@^1.57.0":
+ version "1.57.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.57.0.tgz#969ac7bf16337d5de3808fee6fb5c13eefd99478"
+ integrity sha512-AAVvPDaxCsojmOyVVTyaOcob+bPhtYJ+GbtmmNNCHg2dXYDAEgy3+TYzAfV5fQ08TCZ9DPiKEjDIi2ODh0x/8g==
"@gitlab/ui@^3.0.0":
version "3.0.0"
@@ -2742,6 +2742,11 @@ custom-event@~1.0.0:
resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=
+custom-jquery-matchers@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/custom-jquery-matchers/-/custom-jquery-matchers-2.1.0.tgz#e5988fa9715c416b0986b372563f872d9e91e024"
+ integrity sha512-f2vQrncnwqbeDne9ag/BRjrmG9BxIEKnZ9Z8TyG5l9B8wwyINWd7LvuHDlTkMPqLTd3ghcvqFoTsxjhOP371JQ==
+
cyclist@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"