summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml1
-rw-r--r--.rubocop_todo.yml126
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue2
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js2
-rw-r--r--app/controllers/groups/registry/repositories_controller.rb15
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb14
-rw-r--r--app/finders/projects/prometheus/alerts_finder.rb71
-rw-r--r--app/finders/protected_branches_finder.rb35
-rw-r--r--app/models/project.rb4
-rw-r--r--app/models/protected_branch.rb7
-rw-r--r--app/presenters/projects/prometheus/alert_presenter.rb110
-rw-r--r--app/serializers/container_repositories_serializer.rb1
-rw-r--r--app/services/git/base_hooks_service.rb26
-rw-r--r--changelogs/unreleased/23315-routing-changes-and-pagination-for-container-registry.yml6
-rw-r--r--changelogs/unreleased/37722-configurable-ds-advisory-db.yml5
-rw-r--r--changelogs/unreleased/460-protected-branches-api-search.yml5
-rw-r--r--changelogs/unreleased/fix-do-not-update-private-profile-in-api.yml6
-rw-r--r--changelogs/unreleased/sh-sanitize-pipeline-params.yml5
-rw-r--r--config/routes/group.rb2
-rw-r--r--config/routes/project.rb2
-rw-r--r--db/migrate/20200128141125_add_index_web_hooks_on_group_id.rb17
-rw-r--r--db/schema.rb1
-rw-r--r--doc/api/users.md4
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/pipelines.md177
-rw-r--r--doc/development/redis.md43
-rw-r--r--lib/api/protected_branches.rb7
-rw-r--r--lib/api/users.rb2
-rw-r--r--lib/gitlab/alerting/alert.rb167
-rw-r--r--lib/gitlab/alerting/alert_annotation.rb11
-rw-r--r--lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb2
-rw-r--r--qa/spec/resource/api_fabricator_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/github_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/instance_saml_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/kubernetes_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/ldap_spec.rb6
-rw-r--r--qa/spec/scenario/test/integration/mattermost_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/oauth_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/object_storage_spec.rb2
-rw-r--r--qa/spec/specs/runner_spec.rb2
-rw-r--r--spec/controllers/application_controller_spec.rb2
-rw-r--r--spec/controllers/groups/registry/repositories_controller_spec.rb27
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb2
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb31
-rw-r--r--spec/factories/alerting/alert.rb25
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb4
-rw-r--r--spec/finders/concerns/finder_with_cross_project_access_spec.rb2
-rw-r--r--spec/finders/projects/prometheus/alerts_finder_spec.rb169
-rw-r--r--spec/finders/protected_branches_finder_spec.rb37
-rw-r--r--spec/frontend/environments/environment_external_url_spec.js16
-rw-r--r--spec/helpers/diff_helper_spec.rb4
-rw-r--r--spec/helpers/nav_helper_spec.rb4
-rw-r--r--spec/helpers/sourcegraph_helper_spec.rb2
-rw-r--r--spec/javascripts/environments/environment_external_url_spec.js22
-rw-r--r--spec/lib/container_registry/registry_spec.rb2
-rw-r--r--spec/lib/container_registry/tag_spec.rb18
-rw-r--r--spec/lib/gitlab/alerting/alert_spec.rb226
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/trace/chunked_io_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/trace/section_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/cleanup/project_uploads_spec.rb4
-rw-r--r--spec/lib/gitlab/content_security_policy/config_loader_spec.rb4
-rw-r--r--spec/lib/gitlab/danger/teammate_spec.rb2
-rw-r--r--spec/lib/gitlab/database/count_spec.rb2
-rw-r--r--spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb2
-rw-r--r--spec/lib/gitlab/git_access_spec.rb2
-rw-r--r--spec/lib/gitlab/git_ref_validator_spec.rb4
-rw-r--r--spec/lib/gitlab/gpg_spec.rb4
-rw-r--r--spec/lib/gitlab/legacy_github_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/private_commit_email_spec.rb8
-rw-r--r--spec/lib/gitlab/rugged_instrumentation_spec.rb2
-rw-r--r--spec/lib/gitlab/sanitizers/exif_spec.rb2
-rw-r--r--spec/lib/omni_auth/strategies/jwt_spec.rb2
-rw-r--r--spec/lib/safe_zip/entry_spec.rb4
-rw-r--r--spec/lib/safe_zip/extract_spec.rb2
-rw-r--r--spec/models/badge_spec.rb4
-rw-r--r--spec/models/badges/project_badge_spec.rb4
-rw-r--r--spec/models/ci/artifact_blob_spec.rb2
-rw-r--r--spec/models/ci/persistent_ref_spec.rb6
-rw-r--r--spec/models/ci/runner_spec.rb2
-rw-r--r--spec/models/concerns/avatarable_spec.rb6
-rw-r--r--spec/models/concerns/routable_spec.rb2
-rw-r--r--spec/models/concerns/triggerable_hooks_spec.rb2
-rw-r--r--spec/models/deployment_metrics_spec.rb2
-rw-r--r--spec/models/deployment_spec.rb2
-rw-r--r--spec/models/issue_spec.rb6
-rw-r--r--spec/models/notification_recipient_spec.rb2
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb4
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/issue_message_spec.rb2
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb2
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb2
-rw-r--r--spec/models/project_services/jira_service_spec.rb2
-rw-r--r--spec/models/project_spec.rb14
-rw-r--r--spec/models/protected_branch_spec.rb28
-rw-r--r--spec/models/remote_mirror_spec.rb8
-rw-r--r--spec/models/user_spec.rb10
-rw-r--r--spec/models/wiki_page_spec.rb2
-rw-r--r--spec/presenters/projects/prometheus/alert_presenter_spec.rb235
-rw-r--r--spec/requests/api/graphql_spec.rb2
-rw-r--r--spec/requests/api/issues/get_group_issues_spec.rb2
-rw-r--r--spec/requests/api/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/protected_branches_spec.rb18
-rw-r--r--spec/requests/api/users_spec.rb20
-rw-r--r--spec/serializers/container_repositories_serializer_spec.rb84
-rw-r--r--spec/serializers/diff_file_entity_spec.rb2
-rw-r--r--spec/services/branches/delete_merged_service_spec.rb4
-rw-r--r--spec/services/ci/ensure_stage_service_spec.rb2
-rw-r--r--spec/services/clusters/cleanup/app_service_spec.rb2
-rw-r--r--spec/services/git/branch_push_service_spec.rb21
-rw-r--r--spec/services/labels/available_labels_service_spec.rb4
-rw-r--r--spec/services/notification_service_spec.rb2
-rw-r--r--spec/services/projects/batch_open_issues_count_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb8
-rw-r--r--spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb6
-rw-r--r--spec/services/projects/housekeeping_service_spec.rb2
-rw-r--r--spec/services/projects/open_issues_count_service_spec.rb2
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb2
-rw-r--r--spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb2
-rw-r--r--spec/tasks/gitlab/cleanup_rake_spec.rb6
-rw-r--r--spec/uploaders/gitlab_uploader_spec.rb2
-rw-r--r--spec/uploaders/namespace_file_uploader_spec.rb2
-rw-r--r--spec/workers/create_gpg_signature_worker_spec.rb2
132 files changed, 1743 insertions, 389 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1b76a3088fb..295216a6fea 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,6 @@ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.1
stages:
- sync
- prepare
- - quick-test
- test
- post-test
- review-prepare
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 6648b358557..f6aa0e77005 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -660,129 +660,3 @@ Style/UnneededCondition:
# Cop supports --auto-correct.
Style/UnneededInterpolation:
Enabled: false
-
-RSpec/ReceiveCounts:
- Exclude:
- - 'ee/spec/models/broadcast_message_spec.rb'
- - 'ee/spec/services/geo/project_housekeeping_service_spec.rb'
- - 'ee/spec/services/geo/repository_sync_service_spec.rb'
- - 'spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb'
- - 'spec/lib/gitlab/ci/trace/section_parser_spec.rb'
- - 'spec/lib/gitlab/cleanup/project_uploads_spec.rb'
- - 'spec/lib/gitlab/danger/teammate_spec.rb'
- - 'spec/lib/gitlab/git_access_spec.rb'
- - 'spec/lib/gitlab/gpg_spec.rb'
- - 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
- - 'spec/lib/gitlab/sanitizers/exif_spec.rb'
- - 'spec/models/concerns/avatarable_spec.rb'
- - 'spec/models/concerns/triggerable_hooks_spec.rb'
- - 'spec/requests/api/graphql_spec.rb'
- - 'spec/services/ci/ensure_stage_service_spec.rb'
- - 'spec/services/clusters/cleanup/app_service_spec.rb'
- - 'spec/services/notification_service_spec.rb'
- - 'spec/services/projects/housekeeping_service_spec.rb'
- - 'spec/tasks/gitlab/cleanup_rake_spec.rb'
- - 'spec/uploaders/gitlab_uploader_spec.rb'
- - 'spec/workers/create_gpg_signature_worker_spec.rb'
-
-RSpec/ContextMethod:
- Exclude:
- - 'ee/spec/controllers/ee/projects/autocomplete_sources_controller_spec.rb'
- - 'ee/spec/controllers/groups/autocomplete_sources_controller_spec.rb'
- - 'ee/spec/finders/geo/file_registry_finder_spec.rb'
- - 'ee/spec/helpers/feature_flags_helper_spec.rb'
- - 'ee/spec/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules_spec.rb'
- - 'ee/spec/lib/ee/gitlab/ci/config/entry/trigger_spec.rb'
- - 'ee/spec/lib/elastic/latest/snippet_instance_proxy_spec.rb'
- - 'ee/spec/lib/gitlab/contribution_analytics/data_collector_spec.rb'
- - 'ee/spec/lib/gitlab/geo/replication/file_transfer_spec.rb'
- - 'ee/spec/lib/gitlab/geo/replication/job_artifact_downloader_spec.rb'
- - 'ee/spec/lib/gitlab/geo/replication/job_artifact_retriever_spec.rb'
- - 'ee/spec/lib/gitlab/geo/replication/job_artifact_transfer_spec.rb'
- - 'ee/spec/lib/gitlab/geo/replication/lfs_downloader_spec.rb'
- - 'ee/spec/lib/gitlab/geo/replication/lfs_retriever_spec.rb'
- - 'ee/spec/lib/gitlab/geo/replication/lfs_transfer_spec.rb'
- - 'ee/spec/lib/gitlab/geo_spec.rb'
- - 'ee/spec/models/approval_state_spec.rb'
- - 'ee/spec/models/approval_wrapped_any_approver_rule_spec.rb'
- - 'ee/spec/models/concerns/approval_rule_like_spec.rb'
- - 'ee/spec/models/concerns/elastic/issue_spec.rb'
- - 'ee/spec/models/concerns/elastic/note_spec.rb'
- - 'ee/spec/models/concerns/elastic/project_spec.rb'
- - 'ee/spec/models/concerns/epic_tree_sorting_spec.rb'
- - 'ee/spec/models/concerns/has_timelogs_report_spec.rb'
- - 'ee/spec/models/ee/clusters/applications/prometheus_spec.rb'
- - 'ee/spec/models/ee/clusters/platforms/kubernetes_spec.rb'
- - 'ee/spec/models/user_spec.rb'
- - 'ee/spec/presenters/ci/pipeline_presenter_spec.rb'
- - 'ee/spec/requests/api/epics_spec.rb'
- - 'ee/spec/services/boards/update_service_spec.rb'
- - 'ee/spec/services/ee/boards/issues/list_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/refresh_service_spec.rb'
- - 'ee/spec/services/groups/update_service_spec.rb'
- - 'ee/spec/services/projects/create_from_template_service_spec.rb'
- - 'ee/spec/services/projects/update_service_spec.rb'
- - 'ee/spec/services/update_build_minutes_service_spec.rb'
- - 'ee/spec/support/shared_examples/features/gold_trial_callout_shared_examples.rb'
- - 'ee/spec/support/shared_examples/models/concerns/elastic/limited_indexing_shared_examples.rb'
- - 'qa/spec/ee/scenario/test/integration/group_saml_spec.rb'
- - 'qa/spec/resource/api_fabricator_spec.rb'
- - 'qa/spec/scenario/test/integration/github_spec.rb'
- - 'qa/spec/scenario/test/integration/instance_saml_spec.rb'
- - 'qa/spec/scenario/test/integration/kubernetes_spec.rb'
- - 'qa/spec/scenario/test/integration/ldap_spec.rb'
- - 'qa/spec/scenario/test/integration/mattermost_spec.rb'
- - 'qa/spec/scenario/test/integration/oauth_spec.rb'
- - 'qa/spec/scenario/test/integration/object_storage_spec.rb'
- - 'qa/spec/specs/runner_spec.rb'
- - 'spec/controllers/application_controller_spec.rb'
- - 'spec/controllers/projects/milestones_controller_spec.rb'
- - 'spec/features/projects/blobs/blob_show_spec.rb'
- - 'spec/finders/concerns/finder_with_cross_project_access_spec.rb'
- - 'spec/helpers/diff_helper_spec.rb'
- - 'spec/helpers/nav_helper_spec.rb'
- - 'spec/helpers/sourcegraph_helper_spec.rb'
- - 'spec/lib/container_registry/registry_spec.rb'
- - 'spec/lib/container_registry/tag_spec.rb'
- - 'spec/lib/gitlab/ci/trace/chunked_io_spec.rb'
- - 'spec/lib/gitlab/content_security_policy/config_loader_spec.rb'
- - 'spec/lib/gitlab/database/count_spec.rb'
- - 'spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb'
- - 'spec/lib/gitlab/git_ref_validator_spec.rb'
- - 'spec/lib/gitlab/private_commit_email_spec.rb'
- - 'spec/lib/gitlab/rugged_instrumentation_spec.rb'
- - 'spec/lib/omni_auth/strategies/jwt_spec.rb'
- - 'spec/lib/safe_zip/entry_spec.rb'
- - 'spec/lib/safe_zip/extract_spec.rb'
- - 'spec/models/badge_spec.rb'
- - 'spec/models/badges/project_badge_spec.rb'
- - 'spec/models/ci/artifact_blob_spec.rb'
- - 'spec/models/ci/persistent_ref_spec.rb'
- - 'spec/models/ci/runner_spec.rb'
- - 'spec/models/concerns/routable_spec.rb'
- - 'spec/models/deployment_spec.rb'
- - 'spec/models/issue_spec.rb'
- - 'spec/models/notification_recipient_spec.rb'
- - 'spec/models/project_services/bamboo_service_spec.rb'
- - 'spec/models/project_services/buildkite_service_spec.rb'
- - 'spec/models/project_services/chat_message/issue_message_spec.rb'
- - 'spec/models/project_services/drone_ci_service_spec.rb'
- - 'spec/models/project_services/hipchat_service_spec.rb'
- - 'spec/models/project_services/jira_service_spec.rb'
- - 'spec/models/project_spec.rb'
- - 'spec/models/remote_mirror_spec.rb'
- - 'spec/models/user_spec.rb'
- - 'spec/models/wiki_page_spec.rb'
- - 'spec/requests/api/issues/get_group_issues_spec.rb'
- - 'spec/requests/api/merge_requests_spec.rb'
- - 'spec/serializers/diff_file_entity_spec.rb'
- - 'spec/services/branches/delete_merged_service_spec.rb'
- - 'spec/services/labels/available_labels_service_spec.rb'
- - 'spec/services/projects/batch_open_issues_count_service_spec.rb'
- - 'spec/services/projects/destroy_service_spec.rb'
- - 'spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb'
- - 'spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb'
- - 'spec/services/projects/open_issues_count_service_spec.rb'
- - 'spec/services/quick_actions/interpret_service_spec.rb'
- - 'spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb'
- - 'spec/uploaders/namespace_file_uploader_spec.rb'
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index 7db9898396b..f8bf778b9e7 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -307,7 +307,7 @@ export default {
<a
v-if="titleLink"
:href="titleLink"
- target="blank"
+ target="_blank"
rel="noopener noreferrer"
class="js-cluster-application-title"
>{{ title }}</a
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index 48114f9919c..731c53a7339 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -285,7 +285,7 @@ export default {
ref="viewButton"
v-gl-tooltip.hover
:href="diffFile.view_path"
- target="blank"
+ target="_blank"
class="view-file"
data-track-event="click_toggle_view_sha_button"
data-track-label="diff_toggle_view_sha_button"
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 202363a1dda..267b49e9d98 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -166,7 +166,7 @@ export const setUrlFragment = (url, fragment) => {
export function visitUrl(url, external = false) {
if (external) {
- // Simulate `target="blank" rel="noopener noreferrer"`
+ // Simulate `target="_blank" rel="noopener noreferrer"`
// See https://mathiasbynens.github.io/rel-noopener/
const otherWindow = window.open();
otherWindow.opener = null;
diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb
index a4ef33ecc6a..84c25cfb180 100644
--- a/app/controllers/groups/registry/repositories_controller.rb
+++ b/app/controllers/groups/registry/repositories_controller.rb
@@ -14,13 +14,24 @@ module Groups
track_event(:list_repositories)
- render json: ContainerRepositoriesSerializer
+ serializer = ContainerRepositoriesSerializer
.new(current_user: current_user)
- .represent_read_only(@images)
+
+ if Feature.enabled?(:vue_container_registry_explorer)
+ render json: serializer.with_pagination(request, response)
+ .represent_read_only(@images)
+ else
+ render json: serializer.represent_read_only(@images)
+ end
end
end
end
+ # The show action renders index to allow frontend routing to work on page refresh
+ def show
+ render :index
+ end
+
private
def feature_flag_group_container_registry_browser!
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index 5e933b3b51f..b31a74540e2 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -14,13 +14,23 @@ module Projects
track_event(:list_repositories)
- render json: ContainerRepositoriesSerializer
+ serializer = ContainerRepositoriesSerializer
.new(project: project, current_user: current_user)
- .represent(@images)
+
+ if Feature.enabled?(:vue_container_registry_explorer)
+ render json: serializer.with_pagination(request, response).represent(@images)
+ else
+ render json: serializer.represent(@images)
+ end
end
end
end
+ # The show action renders index to allow frontend routing to work on page refresh
+ def show
+ render :index
+ end
+
def destroy
DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id)
track_event(:delete_repository)
diff --git a/app/finders/projects/prometheus/alerts_finder.rb b/app/finders/projects/prometheus/alerts_finder.rb
new file mode 100644
index 00000000000..3e3b72647c5
--- /dev/null
+++ b/app/finders/projects/prometheus/alerts_finder.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+module Projects
+ module Prometheus
+ # Find Prometheus alerts by +project+, +environment+, +id+,
+ # or any combo thereof.
+ #
+ # Optionally filter by +metric+.
+ #
+ # Arguments:
+ # params:
+ # project: Project | integer
+ # environment: Environment | integer
+ # metric: PrometheusMetric | integer
+ class AlertsFinder
+ def initialize(params = {})
+ unless params[:project] || params[:environment] || params[:id]
+ raise ArgumentError,
+ 'Please provide one or more of the following params: :project, :environment, :id'
+ end
+
+ @params = params
+ end
+
+ # Find all matching alerts
+ #
+ # @return [ActiveRecord::Relation<PrometheusAlert>]
+ def execute
+ relation = by_project(PrometheusAlert)
+ relation = by_environment(relation)
+ relation = by_metric(relation)
+ relation = by_id(relation)
+ relation = ordered(relation)
+
+ relation
+ end
+
+ private
+
+ attr_reader :params
+
+ def by_project(relation)
+ return relation unless params[:project]
+
+ relation.for_project(params[:project])
+ end
+
+ def by_environment(relation)
+ return relation unless params[:environment]
+
+ relation.for_environment(params[:environment])
+ end
+
+ def by_metric(relation)
+ return relation unless params[:metric]
+
+ relation.for_metric(params[:metric])
+ end
+
+ def by_id(relation)
+ return relation unless params[:id]
+
+ relation.id_in(params[:id])
+ end
+
+ def ordered(relation)
+ relation.order_by('id_asc')
+ end
+ end
+ end
+end
diff --git a/app/finders/protected_branches_finder.rb b/app/finders/protected_branches_finder.rb
new file mode 100644
index 00000000000..68e8d2a9f54
--- /dev/null
+++ b/app/finders/protected_branches_finder.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+# ProtectedBranchesFinder
+#
+# Used to filter protected branches by set of params
+#
+# Arguments:
+# project - which project to scope to
+# params:
+# search: string
+class ProtectedBranchesFinder
+ LIMIT = 100
+
+ attr_accessor :project, :params
+
+ def initialize(project, params = {})
+ @project = project
+ @params = params
+ end
+
+ def execute
+ protected_branches = project.limited_protected_branches(LIMIT)
+ protected_branches = by_name(protected_branches)
+
+ protected_branches
+ end
+
+ private
+
+ def by_name(protected_branches)
+ return protected_branches unless params[:search].present?
+
+ protected_branches.by_name(params[:search])
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 78c3114ce9c..816d964519d 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2304,6 +2304,10 @@ class Project < ApplicationRecord
ci_config_path.blank? || ci_config_path == Gitlab::FileDetector::PATTERNS[:gitlab_ci]
end
+ def limited_protected_branches(limit)
+ protected_branches.limit(limit)
+ end
+
private
def closest_namespace_setting(name)
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index 735e2bdea81..94c3b83564f 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -2,6 +2,7 @@
class ProtectedBranch < ApplicationRecord
include ProtectedRef
+ include Gitlab::SQL::Pattern
scope :requiring_code_owner_approval,
-> { where(code_owner_approval_required: true) }
@@ -45,6 +46,12 @@ class ProtectedBranch < ApplicationRecord
# NOOP
#
end
+
+ def self.by_name(query)
+ return none if query.blank?
+
+ where(fuzzy_arel_match(:name, query.downcase))
+ end
end
ProtectedBranch.prepend_if_ee('EE::ProtectedBranch')
diff --git a/app/presenters/projects/prometheus/alert_presenter.rb b/app/presenters/projects/prometheus/alert_presenter.rb
new file mode 100644
index 00000000000..8988c567c5c
--- /dev/null
+++ b/app/presenters/projects/prometheus/alert_presenter.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+module Projects
+ module Prometheus
+ class AlertPresenter < Gitlab::View::Presenter::Delegated
+ RESERVED_ANNOTATIONS = %w(gitlab_incident_markdown title).freeze
+ GENERIC_ALERT_SUMMARY_ANNOTATIONS = %w(monitoring_tool service hosts).freeze
+ MARKDOWN_LINE_BREAK = " \n".freeze
+
+ def full_title
+ [environment_name, alert_title].compact.join(': ')
+ end
+
+ def project_full_path
+ project.full_path
+ end
+
+ def metric_query
+ gitlab_alert&.full_query
+ end
+
+ def environment_name
+ environment&.name
+ end
+
+ def performance_dashboard_link
+ if environment
+ metrics_project_environment_url(project, environment)
+ else
+ metrics_project_environments_url(project)
+ end
+ end
+
+ def starts_at
+ super&.rfc3339
+ end
+
+ def issue_summary_markdown
+ <<~MARKDOWN.chomp
+ #### Summary
+
+ #{metadata_list}
+ #{alert_details}
+ MARKDOWN
+ end
+
+ private
+
+ def alert_title
+ query_title || title
+ end
+
+ def query_title
+ return unless gitlab_alert
+
+ "#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold} for 5 minutes"
+ end
+
+ def metadata_list
+ metadata = []
+
+ metadata << list_item('Start time', starts_at) if starts_at
+ metadata << list_item('full_query', backtick(full_query)) if full_query
+ metadata << list_item(service.label.humanize, service.value) if service
+ metadata << list_item(monitoring_tool.label.humanize, monitoring_tool.value) if monitoring_tool
+ metadata << list_item(hosts.label.humanize, host_links) if hosts
+
+ metadata.join(MARKDOWN_LINE_BREAK)
+ end
+
+ def alert_details
+ if annotation_list.present?
+ <<~MARKDOWN.chomp
+
+ #### Alert Details
+
+ #{annotation_list}
+ MARKDOWN
+ end
+ end
+
+ def annotation_list
+ strong_memoize(:annotation_list) do
+ annotations
+ .reject { |annotation| annotation.label.in?(RESERVED_ANNOTATIONS | GENERIC_ALERT_SUMMARY_ANNOTATIONS) }
+ .map { |annotation| list_item(annotation.label, annotation.value) }
+ .join(MARKDOWN_LINE_BREAK)
+ end
+ end
+
+ def list_item(key, value)
+ "**#{key}:** #{value}".strip
+ end
+
+ def backtick(value)
+ "`#{value}`"
+ end
+
+ GENERIC_ALERT_SUMMARY_ANNOTATIONS.each do |annotation_name|
+ define_method(annotation_name) do
+ annotations.find { |a| a.label == annotation_name }
+ end
+ end
+
+ def host_links
+ Array(hosts.value).join(' ')
+ end
+ end
+ end
+end
diff --git a/app/serializers/container_repositories_serializer.rb b/app/serializers/container_repositories_serializer.rb
index bc35a67ff24..0e9bdee187b 100644
--- a/app/serializers/container_repositories_serializer.rb
+++ b/app/serializers/container_repositories_serializer.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class ContainerRepositoriesSerializer < BaseSerializer
+ include WithPagination
entity ContainerRepositoryEntity
def represent_read_only(resource)
diff --git a/app/services/git/base_hooks_service.rb b/app/services/git/base_hooks_service.rb
index a49983a84fc..ea5b2f401b3 100644
--- a/app/services/git/base_hooks_service.rb
+++ b/app/services/git/base_hooks_service.rb
@@ -81,15 +81,17 @@ module Git
end
def pipeline_params
- {
- before: oldrev,
- after: newrev,
- ref: ref,
- variables_attributes: generate_vars_from_push_options || [],
- push_options: params[:push_options] || {},
- checkout_sha: Gitlab::DataBuilder::Push.checkout_sha(
- project.repository, newrev, ref)
- }
+ strong_memoize(:pipeline_params) do
+ {
+ before: oldrev,
+ after: newrev,
+ ref: ref,
+ variables_attributes: generate_vars_from_push_options || [],
+ push_options: params[:push_options] || {},
+ checkout_sha: Gitlab::DataBuilder::Push.checkout_sha(
+ project.repository, newrev, ref)
+ }
+ end
end
def ci_variables_from_push_options
@@ -156,12 +158,16 @@ module Git
project_path: project.full_path,
message: "Error creating pipeline",
errors: exception.to_s,
- pipeline_params: pipeline_params
+ pipeline_params: sanitized_pipeline_params
}
logger.warn(data)
end
+ def sanitized_pipeline_params
+ pipeline_params.except(:push_options)
+ end
+
def logger
if Gitlab::Runtime.sidekiq?
Sidekiq.logger
diff --git a/changelogs/unreleased/23315-routing-changes-and-pagination-for-container-registry.yml b/changelogs/unreleased/23315-routing-changes-and-pagination-for-container-registry.yml
new file mode 100644
index 00000000000..62a60cc5dbd
--- /dev/null
+++ b/changelogs/unreleased/23315-routing-changes-and-pagination-for-container-registry.yml
@@ -0,0 +1,6 @@
+---
+title: Add show routes for group and project repositories_controllers and add pagination
+ to the index responses
+merge_request: 23151
+author:
+type: added
diff --git a/changelogs/unreleased/37722-configurable-ds-advisory-db.yml b/changelogs/unreleased/37722-configurable-ds-advisory-db.yml
new file mode 100644
index 00000000000..c03927b0902
--- /dev/null
+++ b/changelogs/unreleased/37722-configurable-ds-advisory-db.yml
@@ -0,0 +1,5 @@
+---
+title: 'Add CI variables to configure bundler-audit advisory database (Dependency Scanning)'
+merge_request: 23717
+author:
+type: added
diff --git a/changelogs/unreleased/460-protected-branches-api-search.yml b/changelogs/unreleased/460-protected-branches-api-search.yml
new file mode 100644
index 00000000000..ed9d89a6a64
--- /dev/null
+++ b/changelogs/unreleased/460-protected-branches-api-search.yml
@@ -0,0 +1,5 @@
+---
+title: Add search support for protected branches API
+merge_request: 24137
+author:
+type: added
diff --git a/changelogs/unreleased/fix-do-not-update-private-profile-in-api.yml b/changelogs/unreleased/fix-do-not-update-private-profile-in-api.yml
new file mode 100644
index 00000000000..f2fa26176b6
--- /dev/null
+++ b/changelogs/unreleased/fix-do-not-update-private-profile-in-api.yml
@@ -0,0 +1,6 @@
+---
+title: Fix inconditionally setting user profile to public when updating via
+ API and private_profile parameter is not present in the request
+merge_request: 24456
+author: Diego Louzán
+type: fixed
diff --git a/changelogs/unreleased/sh-sanitize-pipeline-params.yml b/changelogs/unreleased/sh-sanitize-pipeline-params.yml
new file mode 100644
index 00000000000..93e99b18ffd
--- /dev/null
+++ b/changelogs/unreleased/sh-sanitize-pipeline-params.yml
@@ -0,0 +1,5 @@
+---
+title: Redact push options from error logs
+merge_request: 24540
+author:
+type: fixed
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 8f572a685d8..68e239faf6d 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -76,7 +76,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
end
end
- resources :container_registries, only: [:index], controller: 'registry/repositories'
+ resources :container_registries, only: [:index, :show], controller: 'registry/repositories'
end
scope(path: '*id',
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 3f3d7452a84..82f998f185c 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -371,7 +371,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
- resources :container_registry, only: [:index, :destroy],
+ resources :container_registry, only: [:index, :destroy, :show],
controller: 'registry/repositories'
namespace :registry do
diff --git a/db/migrate/20200128141125_add_index_web_hooks_on_group_id.rb b/db/migrate/20200128141125_add_index_web_hooks_on_group_id.rb
new file mode 100644
index 00000000000..8c7f6426587
--- /dev/null
+++ b/db/migrate/20200128141125_add_index_web_hooks_on_group_id.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexWebHooksOnGroupId < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :web_hooks, :group_id, where: "type = 'GroupHook'"
+ end
+
+ def down
+ remove_concurrent_index :web_hooks, :group_id, where: "type = 'GroupHook'"
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 79c00c10a2d..f55f3df31cf 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -4477,6 +4477,7 @@ ActiveRecord::Schema.define(version: 2020_02_05_143231) do
t.string "encrypted_token_iv"
t.string "encrypted_url"
t.string "encrypted_url_iv"
+ t.index ["group_id"], name: "index_web_hooks_on_group_id", where: "((type)::text = 'GroupHook'::text)"
t.index ["project_id"], name: "index_web_hooks_on_project_id"
t.index ["type"], name: "index_web_hooks_on_type"
end
diff --git a/doc/api/users.md b/doc/api/users.md
index d77df9bc6c7..e147637ca59 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -385,7 +385,7 @@ Parameters:
- `skip_confirmation` (optional) - Skip confirmation - true or false (default)
- `external` (optional) - Flags the user as external - true or false (default)
- `avatar` (optional) - Image file for user's avatar
-- `private_profile` (optional) - User's profile is private - true or false (default)
+- `private_profile` (optional) - User's profile is private - true, false (default), or null (will be converted to false)
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user **(STARTER)**
- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user **(STARTER)**
@@ -423,7 +423,7 @@ Parameters:
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user
- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user
- `avatar` (optional) - Image file for user's avatar
-- `private_profile` (optional) - User's profile is private - true or false (default)
+- `private_profile` (optional) - User's profile is private - true, false (default), or null (will be converted to false)
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user **(STARTER)**
- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user **(STARTER)**
- `note` (optional) - Admin notes for this user **(STARTER)**
diff --git a/doc/development/README.md b/doc/development/README.md
index f94da66085b..ba1714b2746 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -83,6 +83,7 @@ Complementary reads:
- [Cycle Analytics development guide](cycle_analytics.md)
- [Issue types vs first-class types](issue_types.md)
- [Application limits](application_limits.md)
+- [Redis guidelines](redis.md)
## Performance guides
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index 42b4e7385dc..32b4c97cb62 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -19,9 +19,6 @@ The current stages are:
<https://gitlab.com/gitlab-org/gitlab-foss>.
- `prepare`: This stage includes jobs that prepare artifacts that are needed by
jobs in subsequent stages.
-- `quick-test`: This stage includes test jobs that should run first and fail the
- pipeline early (currently used to run Geo tests when the branch name starts
- with `geo-`, `geo/`, or ends with `-geo`).
- `test`: This stage includes most of the tests, DB/migration jobs, and static analysis jobs.
- `post-test`: This stage includes jobs that build reports or gather data from
the `test` stage's jobs (e.g. coverage, Knapsack metadata etc.).
@@ -138,54 +135,109 @@ duplicating the `if` conditions and `changes` patterns lists since they cannot b
**If you update an `if` condition or `changes`
patterns list, make sure to mass-update those across all the CI config files (i.e. `.gitlab/ci/*.yml`).**
-### Canonical commits only
+### Canonical/security namespace merge requests only
-This condition limits jobs creation to commits under the `gitlab-org/` top-level group
-on GitLab.com only. This is similar to the `.only:variables-canonical-dot-com` CI definition:
+This condition limits jobs creation to merge requests under the `gitlab-org/` top-level group
+on GitLab.com only (i.e. this won't run for `master`, stable or auto-deploy branches).
+This is similar to the `.only:variables-canonical-dot-com` + `only:refs: [merge_requests]`
+CI definitions.
-```yaml
-.if-canonical-gitlab: &if-canonical-gitlab
- if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/)/'
-```
+The definition for `if-canonical-dot-com-gitlab-org-groups-merge-request` can be
+seen in <https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/docs.gitlab-ci.yml>.
-### Canonical merge requests only
+### Canonical/security namespace tags only
-Same as the "Canonical commits only" condition above but further limits jobs creation
-to merge requests only (i.e. this won't run for `master`, stable or auto-deploy branches).
-This is similar to the `.only:variables-canonical-dot-com` + `.except:refs-master-tags-stable-deploy`
-CI definitions:
+This condition limits jobs creation to tags under the `gitlab-org/` top-level group
+on GitLab.com only.
+This is similar to the `.only:variables-canonical-dot-com` + `only:refs: [tags]` CI definition:
-```yaml
-.if-canonical-gitlab-merge-request: &if-canonical-gitlab-merge-request
- if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/)/ && $CI_MERGE_REQUEST_IID'
-```
+The definition for `if-canonical-dot-com-gitlab-org-groups-tag` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/cng.gitlab-ci.yml>.
+
+### Canonical namespace `master` only
+
+This condition limits jobs creation to `master` pipelines for the `gitlab-org` top-level group
+on GitLab.com only.
+This is similar to the `.only:variables-canonical-dot-com` + `only:refs: [master]` CI definition:
+
+The definition for `if-canonical-dot-com-gitlab-org-group-master-refs` can be
+seen in <https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/pages.gitlab-ci.yml>.
+
+### Canonical namespace schedules only
+
+This condition limits jobs creation to scheduled pipelines for the `gitlab-org` top-level group
+on GitLab.com only.
+This is similar to the `.only:variables-canonical-dot-com` + `only:refs: [schedules]` CI definition:
+
+The definition for `if-canonical-dot-com-gitlab-org-group-schedule` can be seen
+in <https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/qa.gitlab-ci.yml>.
+
+### Not canonical/security namespace
+
+This condition matches if the project isn't in the canonical/security namespace.
+Useful to **not** create a job if the project is a fork, or in other words, when
+a job should only run in the canonical projects.
+
+The definition for `if-not-canonical-namespace` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml>.
+
+### Not EE
+
+This condition matches if the project isn't EE. Useful to **not** create a job if
+the project is GitLab, or in other words, when a job should only run in the GitLab
+FOSS project.
+
+The definition for `if-not-ee` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml>.
+
+### Default refs only
+
+This condition is the equivalent of `.default-only`.
+
+The definition for `if-default-refs` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml>.
+
+### `master` refs only
+
+This condition is the equivalent of `only:refs: [master]`.
+
+The definition for `if-master-refs` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml>.
### Code changes patterns
Similar patterns as for `.only:changes-code`:
-```yaml
-.code-patterns: &code-patterns
- - ...
-```
+The definition for `code-patterns` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/qa.gitlab-ci.yml>.
### QA changes patterns
Similar patterns as for `.only:changes-qa`:
-```yaml
-.qa-patterns: &qa-patterns
- - ...
-```
+The definition for `qa-patterns` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/qa.gitlab-ci.yml>.
+
+### Docs changes patterns
+
+Similar patterns as for `.only:changes-docs`:
+
+The definition for `docs-patterns` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/docs.gitlab-ci.yml>.
### Code and QA changes patterns
Similar patterns as for `.only:changes-code-qa`:
-```yaml
-.code-qa-patterns: &code-qa-patterns
- - ...
-```
+The definition for `code-qa-patterns` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/review.gitlab-ci.yml>.
+
+### Code, backstage and QA changes patterns
+
+Similar patterns as for `.only:changes-code-backstage-qa`:
+
+The definition for `code-backstage-qa-patterns` can be seen in
+<https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml>.
## Directed acyclic graph
@@ -195,21 +247,21 @@ execute jobs out of order for the following jobs:
```mermaid
graph RL;
A[setup-test-env];
- B["gitlab:assets:compile pull-push-cache<br/>(master only)"];
- C[gitlab:assets:compile pull-cache];
+ B["gitlab:assets:compile pull-push-cache<br/>(canonical master only)"];
+ C["gitlab:assets:compile pull-cache<br/>(canonical default refs only)"];
D["cache gems<br/>(master and tags only)"];
E[review-build-cng];
F[build-qa-image];
G[review-deploy];
G2["schedule:review-deploy<br/>(master only)"];
- H[karma];
- I[jest];
+ I["karma, jest, webpack-dev-server, static-analysis"];
+ I2["karma-foss, jest-foss<br/>(EE default refs only)"];
J["compile-assets pull-push-cache<br/>(master only)"];
+ J2["compile-assets pull-push-cache foss<br/>(EE master only)"];
K[compile-assets pull-cache];
- L[webpack-dev-server];
+ K2["compile-assets pull-cache foss<br/>(EE default refs only)"];
M[coverage];
- N[pages];
- O[static-analysis];
+ N["pages (master only)"];
Q[package-and-qa];
S["RSpec<br/>(e.g. rspec unit pg9)"]
T[retrieve-tests-metadata];
@@ -220,58 +272,55 @@ subgraph "`prepare` stage"
C
F
K
+ K2
J
+ J2
T
end
subgraph "`test` stage"
- D --> |needs| A;
- H -.-> |needs and depends on| A;
- H -.-> |needs and depends on| K;
+ D -.-> |needs| A;
I -.-> |needs and depends on| A;
I -.-> |needs and depends on| K;
+ I2 -.-> |needs and depends on| A;
+ I2 -.-> |needs and depends on| K;
L -.-> |needs and depends on| A;
- L -.-> |needs and depends on| K;
- O -.-> |needs and depends on| A;
- O -.-> |needs and depends on| K;
S -.-> |needs and depends on| A;
S -.-> |needs and depends on| K;
S -.-> |needs and depends on| T;
- downtime_check --> |needs and depends on| A;
- db:* --> |needs| A;
- gitlab:setup --> |needs| A;
- downtime_check --> |needs and depends on| A;
- graphql-docs-verify --> |needs| A;
+ L["db:*, gitlab:setup, graphql-docs-verify, downtime_check"] -.-> |needs| A;
+ end
+
+subgraph "`post-test` stage"
+ M --> |happens after| S
end
subgraph "`review-prepare` stage"
- E --> |needs| C;
- X["schedule:review-build-cng<br/>(master schedule only)"] --> |needs| C;
+ E -.-> |needs| C;
+ E2["schedule:review-build-cng<br/>(master schedule only)"] -.-> |needs| C;
end
subgraph "`review` stage"
- G
- G2
+ G --> |happens after| E
+ G2 --> |happens after| E2
end
subgraph "`qa` stage"
- Q --> |needs| C;
- Q --> |needs| F;
- review-qa-smoke -.-> |needs and depends on| G;
- review-qa-all -.-> |needs and depends on| G;
- review-performance -.-> |needs and depends on| G;
- X2["schedule:review-performance<br/>(master only)"] -.-> |needs and depends on| G2;
- dast -.-> |needs and depends on| G;
+ Q -.-> |needs| C;
+ Q -.-> |needs| F;
+ QA1["review-qa-smoke, review-qa-all, review-performance, dast"] -.-> |needs and depends on| G;
+ QA2["schedule:review-performance<br/>(master only)"] -.-> |needs and depends on| G2;
end
-subgraph "`post-test` stage"
- M
- end
+subgraph "`post-qa` stage"
+ PQA1["parallel-spec-reports"] -.-> |depends on `review-qa-all`| QA1;
+ end
subgraph "`pages` stage"
N -.-> |depends on| C;
- N -.-> |depends on| H;
+ N -.-> |depends on karma| I;
N -.-> |depends on| M;
+ N --> |happens after| PQA1
end
```
diff --git a/doc/development/redis.md b/doc/development/redis.md
new file mode 100644
index 00000000000..a4a87155f5a
--- /dev/null
+++ b/doc/development/redis.md
@@ -0,0 +1,43 @@
+# Redis guidelines
+
+GitLab uses [Redis](https://redis.io) for three distinct purposes:
+
+- Caching via `Rails.cache`.
+- As a job processing queue with [Sidekiq](sidekiq_style_guide.md).
+- To manage the shared application state.
+
+Every application process is configured to use the same Redis servers, so they
+can be used for inter-process communication in cases where [PostgreSQL](sql.md)
+is less appropriate, for example, transient state or data that is written much
+more often than it is read.
+
+If [Geo](geo.md) is enabled, each Geo node gets its own, independent Redis
+database.
+
+## Key naming
+
+Redis is a flat namespace with no hierarchy, which means we must pay attention
+to key names to avoid collisions. Typically we use colon-separated elements to
+provide a semblence of structure at application level. An example might be
+`projects:1:somekey`.
+
+Although we split our Redis usage into three separate purposes, and those may
+map to separate Redis servers in a [Highly Available](../administration/high_availability/redis.md)
+configuration, the default Omnibus and GDK setups share a single Redis server.
+This means that keys should **always** be globally unique across the three
+purposes.
+
+It is usually better to use immutable identifiers - project ID rather than
+full path, for instance - in Redis key names. If full path is used, the key will
+stop being consulted if the project is renamed. If the contents of the key are
+invalidated by a name change, it is better to include a hook that will expire
+the entry, instead of relying on the key changing.
+
+We don't use [Redis Cluster](https://redis.io/topics/cluster-tutorial) at the
+moment, but may wish to in the future: [#118820](https://gitlab.com/gitlab-org/gitlab/issues/118820).
+
+This imposes an additional constraint on naming: where GitLab is performing
+operations that require several keys to be held on the same Redis server - for
+instance, diffing two sets held in Redis - the keys should ensure that by
+enclosing the changeable parts in curly braces, such as, `project:{1}:set_a` and
+`project:{1}:set_b`.
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index c7665c20234..1fd86d1e720 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -19,10 +19,15 @@ module API
end
params do
use :pagination
+ optional :search, type: String, desc: 'Search for a protected branch by name'
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_branches' do
- protected_branches = user_project.protected_branches.preload(:push_access_levels, :merge_access_levels)
+ protected_branches =
+ ProtectedBranchesFinder
+ .new(user_project, params)
+ .execute
+ .preload(:push_access_levels, :merge_access_levels)
present paginate(protected_branches), with: Entities::ProtectedBranch, project: user_project
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index eba7c50435c..da64ff7e306 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -52,7 +52,7 @@ module API
optional :external, type: Boolean, desc: 'Flag indicating the user is an external user'
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
optional :avatar, type: File, desc: 'Avatar image for user' # rubocop:disable Scalability/FileUploads
- optional :private_profile, type: Boolean, default: false, desc: 'Flag indicating the user has a private profile'
+ optional :private_profile, type: Boolean, desc: 'Flag indicating the user has a private profile'
all_or_none_of :extern_uid, :provider
use :optional_params_ee
diff --git a/lib/gitlab/alerting/alert.rb b/lib/gitlab/alerting/alert.rb
new file mode 100644
index 00000000000..531307b93d4
--- /dev/null
+++ b/lib/gitlab/alerting/alert.rb
@@ -0,0 +1,167 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Alerting
+ class Alert
+ include ActiveModel::Model
+ include Gitlab::Utils::StrongMemoize
+ include Presentable
+
+ attr_accessor :project, :payload
+
+ def gitlab_alert
+ strong_memoize(:gitlab_alert) do
+ parse_gitlab_alert_from_payload
+ end
+ end
+
+ def metric_id
+ strong_memoize(:metric_id) do
+ payload&.dig('labels', 'gitlab_alert_id')
+ end
+ end
+
+ def title
+ strong_memoize(:title) do
+ gitlab_alert&.title || parse_title_from_payload
+ end
+ end
+
+ def description
+ strong_memoize(:description) do
+ parse_description_from_payload
+ end
+ end
+
+ def environment
+ strong_memoize(:environment) do
+ gitlab_alert&.environment || parse_environment_from_payload
+ end
+ end
+
+ def annotations
+ strong_memoize(:annotations) do
+ parse_annotations_from_payload || []
+ end
+ end
+
+ def starts_at
+ strong_memoize(:starts_at) do
+ parse_datetime_from_payload('startsAt')
+ end
+ end
+
+ def starts_at_raw
+ strong_memoize(:starts_at_raw) do
+ payload&.dig('startsAt')
+ end
+ end
+
+ def ends_at
+ strong_memoize(:ends_at) do
+ parse_datetime_from_payload('endsAt')
+ end
+ end
+
+ def full_query
+ strong_memoize(:full_query) do
+ gitlab_alert&.full_query || parse_expr_from_payload
+ end
+ end
+
+ def alert_markdown
+ strong_memoize(:alert_markdown) do
+ parse_alert_markdown_from_payload
+ end
+ end
+
+ def status
+ strong_memoize(:status) do
+ payload&.dig('status')
+ end
+ end
+
+ def firing?
+ status == 'firing'
+ end
+
+ def resolved?
+ status == 'resolved'
+ end
+
+ def gitlab_managed?
+ metric_id.present?
+ end
+
+ def valid?
+ payload.respond_to?(:dig) && project && title && starts_at
+ end
+
+ def present
+ super(presenter_class: Projects::Prometheus::AlertPresenter)
+ end
+
+ private
+
+ def parse_environment_from_payload
+ environment_name = payload&.dig('labels', 'gitlab_environment_name')
+
+ return unless environment_name
+
+ EnvironmentsFinder.new(project, nil, { name: environment_name })
+ .find
+ &.first
+ end
+
+ def parse_gitlab_alert_from_payload
+ return unless metric_id
+
+ Projects::Prometheus::AlertsFinder
+ .new(project: project, metric: metric_id)
+ .execute
+ .first
+ end
+
+ def parse_title_from_payload
+ payload&.dig('annotations', 'title') ||
+ payload&.dig('annotations', 'summary') ||
+ payload&.dig('labels', 'alertname')
+ end
+
+ def parse_description_from_payload
+ payload&.dig('annotations', 'description')
+ end
+
+ def parse_annotations_from_payload
+ payload&.dig('annotations')&.map do |label, value|
+ Alerting::AlertAnnotation.new(label: label, value: value)
+ end
+ end
+
+ def parse_datetime_from_payload(field)
+ value = payload&.dig(field)
+ return unless value
+
+ Time.rfc3339(value)
+ rescue ArgumentError
+ end
+
+ # Parses `g0.expr` from `generatorURL`.
+ #
+ # Example: http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1
+ def parse_expr_from_payload
+ url = payload&.dig('generatorURL')
+ return unless url
+
+ uri = URI(url)
+
+ Rack::Utils.parse_query(uri.query).fetch('g0.expr')
+ rescue URI::InvalidURIError, KeyError
+ end
+
+ def parse_alert_markdown_from_payload
+ payload&.dig('annotations', 'gitlab_incident_markdown')
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/alerting/alert_annotation.rb b/lib/gitlab/alerting/alert_annotation.rb
new file mode 100644
index 00000000000..a4b3a97b08c
--- /dev/null
+++ b/lib/gitlab/alerting/alert_annotation.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Alerting
+ class AlertAnnotation
+ include ActiveModel::Model
+
+ attr_accessor :label, :value
+ end
+ end
+end
diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
index 225fb7e5606..5ff6413898f 100644
--- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
@@ -57,6 +57,8 @@ dependency_scanning:
PIP_REQUIREMENTS_FILE \
MAVEN_CLI_OPTS \
BUNDLER_AUDIT_UPDATE_DISABLED \
+ BUNDLER_AUDIT_ADVISORY_DB_URL \
+ BUNDLER_AUDIT_ADVISORY_DB_REF_NAME \
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
index 6c7f80705e2..57d2c02a27b 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
@@ -3,7 +3,7 @@
module QA
context 'Plan', :reliable do
describe 'check xss occurence in @mentions in issues', :requires_admin do
- it 'user mentions a user in comment' do
+ it 'mentions a user in a comment' do
QA::Runtime::Env.personal_access_token = QA::Runtime::Env.admin_personal_access_token
unless QA::Runtime::Env.personal_access_token
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb
index fd00e010b85..d075dc742e2 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb
@@ -18,7 +18,7 @@ module QA
push_commit('Initial commit')
end
- it 'user closes an issue by pushing commit' do
+ it 'closes an issue by pushing a commit' do
push_commit("Closes ##{issue_id}", false)
issue.visit!
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
index a2b7904a84d..33d2c7026b3 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
@@ -17,7 +17,7 @@ module QA
end
end
- it 'user collapses and expands reply for comments in an issue' do
+ it 'collapses and expands reply for comments in an issue' do
Page::Project::Issue::Show.perform do |show|
one_reply = "1 reply"
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
index c4a8d2c4e20..4667eb6c587 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
@@ -9,7 +9,7 @@ module QA
Resource::Issue.fabricate_via_api!.visit!
end
- it 'user comments on an issue and edits the comment' do
+ it 'comments on an issue and edits the comment' do
Page::Project::Issue::Show.perform do |show|
first_version_of_comment = 'First version of the comment'
second_version_of_comment = 'Second version of the comment'
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
index 0ea81483a66..1c741a2e8bf 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -7,7 +7,7 @@ module QA
Flow::Login.sign_in
end
- it 'user creates an issue' do
+ it 'creates an issue' do
issue = Resource::Issue.fabricate_via_browser_ui!
Page::Project::Menu.perform(&:click_issues)
@@ -27,7 +27,7 @@ module QA
Resource::Issue.fabricate_via_api!.visit!
end
- it 'user comments on an issue with an attachment' do
+ it 'comments on an issue with an attachment' do
Page::Project::Issue::Show.perform do |show|
show.comment('See attached banana for scale', attachment: file_to_attach)
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
index f1013d38a1f..b7687f785a8 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
@@ -9,7 +9,7 @@ module QA
Resource::Issue.fabricate_via_api!.visit!
end
- it 'user filters comments and activities in an issue' do
+ it 'filters comments and activities in an issue' do
Page::Project::Issue::Show.perform do |show|
my_own_comment = "My own comment"
made_the_issue_confidential = "made the issue confidential"
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
index 6c851fd8141..9b46a066c8e 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
@@ -13,7 +13,7 @@ module QA
end.project.visit!
end
- it 'user sees issue suggestions when creating a new issue' do
+ it 'shows issue suggestions when creating a new issue' do
Page::Project::Show.perform(&:go_to_new_issue)
Page::Project::Issue::New.perform do |new_page|
new_page.add_title("issue")
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
index a76cb57b4a7..3e575517ecb 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
@@ -20,7 +20,7 @@ module QA
end.visit!
end
- it 'user mentions another user in an issue' do
+ it 'mentions another user in an issue' do
Page::Project::Issue::Show.perform do |show|
at_username = "@#{@user.username}"
diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb
index a5ed4422f6e..eb2bdd1be64 100644
--- a/qa/spec/resource/api_fabricator_spec.rb
+++ b/qa/spec/resource/api_fabricator_spec.rb
@@ -120,7 +120,7 @@ describe QA::Resource::ApiFabricator do
end
end
- context '#transform_api_resource' do
+ describe '#transform_api_resource' do
let(:resource) do
Class.new do
def self.name
diff --git a/qa/spec/scenario/test/integration/github_spec.rb b/qa/spec/scenario/test/integration/github_spec.rb
index 6112ba7c694..b2d577bd552 100644
--- a/qa/spec/scenario/test/integration/github_spec.rb
+++ b/qa/spec/scenario/test/integration/github_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::Github do
- context '#perform' do
+ describe '#perform' do
let(:env) { spy('Runtime::Env') }
before do
diff --git a/qa/spec/scenario/test/integration/instance_saml_spec.rb b/qa/spec/scenario/test/integration/instance_saml_spec.rb
index cb8a6a630cc..15f15b2e643 100644
--- a/qa/spec/scenario/test/integration/instance_saml_spec.rb
+++ b/qa/spec/scenario/test/integration/instance_saml_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::InstanceSAML do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:instance_saml] }
end
diff --git a/qa/spec/scenario/test/integration/kubernetes_spec.rb b/qa/spec/scenario/test/integration/kubernetes_spec.rb
index cb43994b229..51ee7b9acff 100644
--- a/qa/spec/scenario/test/integration/kubernetes_spec.rb
+++ b/qa/spec/scenario/test/integration/kubernetes_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::Kubernetes do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:kubernetes] }
end
diff --git a/qa/spec/scenario/test/integration/ldap_spec.rb b/qa/spec/scenario/test/integration/ldap_spec.rb
index 86747cd8eb7..c493cde6c7a 100644
--- a/qa/spec/scenario/test/integration/ldap_spec.rb
+++ b/qa/spec/scenario/test/integration/ldap_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::LDAPNoTLS do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:ldap_no_tls] }
end
@@ -9,7 +9,7 @@ describe QA::Scenario::Test::Integration::LDAPNoTLS do
end
describe QA::Scenario::Test::Integration::LDAPNoServer do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:ldap_no_server] }
end
@@ -17,7 +17,7 @@ describe QA::Scenario::Test::Integration::LDAPNoServer do
end
describe QA::Scenario::Test::Integration::LDAPTLS do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:ldap_tls] }
end
diff --git a/qa/spec/scenario/test/integration/mattermost_spec.rb b/qa/spec/scenario/test/integration/mattermost_spec.rb
index 4e75e72f4d2..4452e890ebe 100644
--- a/qa/spec/scenario/test/integration/mattermost_spec.rb
+++ b/qa/spec/scenario/test/integration/mattermost_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::Mattermost do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:args) { %w[gitlab_address mattermost_address] }
let(:args) do
diff --git a/qa/spec/scenario/test/integration/oauth_spec.rb b/qa/spec/scenario/test/integration/oauth_spec.rb
index c1c320be576..ab7ea905a29 100644
--- a/qa/spec/scenario/test/integration/oauth_spec.rb
+++ b/qa/spec/scenario/test/integration/oauth_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::OAuth do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:oauth] }
end
diff --git a/qa/spec/scenario/test/integration/object_storage_spec.rb b/qa/spec/scenario/test/integration/object_storage_spec.rb
index 2b7188223e0..8b4367bee32 100644
--- a/qa/spec/scenario/test/integration/object_storage_spec.rb
+++ b/qa/spec/scenario/test/integration/object_storage_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::ObjectStorage do
- context '#perform' do
+ describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:object_storage] }
end
diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb
index 3d98f03a982..1a3efe0b46c 100644
--- a/qa/spec/specs/runner_spec.rb
+++ b/qa/spec/specs/runner_spec.rb
@@ -11,7 +11,7 @@ describe QA::Specs::Runner do
end
end
- context '#perform' do
+ describe '#perform' do
before do
allow(QA::Runtime::Browser).to receive(:configure!)
end
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index c1cfe9f20d2..bdac7369780 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -896,7 +896,7 @@ describe ApplicationController do
end
end
- context '#set_current_context' do
+ describe '#set_current_context' do
controller(described_class) do
def index
Labkit::Context.with_context do |context|
diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb
index 9463483b7b0..eb702d65325 100644
--- a/spec/controllers/groups/registry/repositories_controller_spec.rb
+++ b/spec/controllers/groups/registry/repositories_controller_spec.rb
@@ -14,7 +14,7 @@ describe Groups::Registry::RepositoriesController do
sign_in(user)
end
- context 'GET #index' do
+ shared_examples 'renders a list of repositories' do
context 'when container registry is enabled' do
it 'show index page' do
expect(Gitlab::Tracking).not_to receive(:event)
@@ -33,6 +33,7 @@ describe Groups::Registry::RepositoriesController do
}
expect(response).to match_response_schema('registry/repositories')
+ expect(response).to include_pagination_headers
end
it 'returns a list of projects for json format' do
@@ -89,5 +90,29 @@ describe Groups::Registry::RepositoriesController do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ context 'with :vue_container_registry_explorer feature flag disabled' do
+ before do
+ stub_feature_flags(vue_container_registry_explorer: false)
+ end
+
+ it 'has the correct response schema' do
+ get :index, params: {
+ group_id: group,
+ format: :json
+ }
+
+ expect(response).to match_response_schema('registry/repositories')
+ expect(response).not_to include_pagination_headers
+ end
+ end
+ end
+
+ context 'GET #index' do
+ it_behaves_like 'renders a list of repositories'
+ end
+
+ context 'GET #show' do
+ it_behaves_like 'renders a list of repositories'
end
end
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 3efdeda6171..6b698c6da66 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -245,7 +245,7 @@ describe Projects::MilestonesController do
end
end
- context '#participants' do
+ describe '#participants' do
render_views
context "when guest user" do
diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb
index 4e832a478af..5b9c0211b39 100644
--- a/spec/controllers/projects/registry/repositories_controller_spec.rb
+++ b/spec/controllers/projects/registry/repositories_controller_spec.rb
@@ -16,7 +16,7 @@ describe Projects::Registry::RepositoriesController do
project.add_developer(user)
end
- describe 'GET index' do
+ shared_examples 'renders a list of repositories' do
context 'when root container repository exists' do
before do
create(:container_repository, :root, project: project)
@@ -58,6 +58,7 @@ describe Projects::Registry::RepositoriesController do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('registry/repositories')
+ expect(response).to include_pagination_headers
end
end
@@ -84,9 +85,33 @@ describe Projects::Registry::RepositoriesController do
end
end
end
+
+ context 'with :vue_container_registry_explorer feature flag disabled' do
+ before do
+ stub_feature_flags(vue_container_registry_explorer: false)
+ stub_container_registry_tags(repository: project.full_path,
+ tags: %w[rc1 latest])
+ end
+
+ it 'json has a list of projects' do
+ go_to_index(format: :json)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ expect(response).not_to include_pagination_headers
+ end
+ end
+ end
+
+ describe 'GET #index' do
+ it_behaves_like 'renders a list of repositories'
+ end
+
+ describe 'GET #show' do
+ it_behaves_like 'renders a list of repositories'
end
- describe 'DELETE destroy' do
+ describe 'DELETE #destroy' do
context 'when root container repository exists' do
let!(:repository) do
create(:container_repository, :root, project: project)
@@ -115,7 +140,7 @@ describe Projects::Registry::RepositoriesController do
end
context 'when user does not have access to registry' do
- describe 'GET index' do
+ describe 'GET #index' do
it 'responds with 404' do
go_to_index
diff --git a/spec/factories/alerting/alert.rb b/spec/factories/alerting/alert.rb
new file mode 100644
index 00000000000..285bb14efa2
--- /dev/null
+++ b/spec/factories/alerting/alert.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :alerting_alert, class: 'Gitlab::Alerting::Alert' do
+ project
+ payload { {} }
+
+ transient do
+ metric_id { nil }
+
+ after(:build) do |alert, evaluator|
+ unless alert.payload.key?('startsAt')
+ alert.payload['startsAt'] = Time.now.rfc3339
+ end
+
+ if metric_id = evaluator.metric_id
+ alert.payload['labels'] ||= {}
+ alert.payload['labels']['gitlab_alert_id'] = metric_id.to_s
+ end
+ end
+ end
+
+ skip_create
+ end
+end
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index e714d0f7cad..0ff3e45c956 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -453,7 +453,7 @@ describe 'File blob', :js do
end
end
- context '.gitlab-ci.yml' do
+ describe '.gitlab-ci.yml' do
before do
project.add_maintainer(project.creator)
@@ -481,7 +481,7 @@ describe 'File blob', :js do
end
end
- context '.gitlab/route-map.yml' do
+ describe '.gitlab/route-map.yml' do
before do
project.add_maintainer(project.creator)
diff --git a/spec/finders/concerns/finder_with_cross_project_access_spec.rb b/spec/finders/concerns/finder_with_cross_project_access_spec.rb
index 6ba98b79176..f3365309b05 100644
--- a/spec/finders/concerns/finder_with_cross_project_access_spec.rb
+++ b/spec/finders/concerns/finder_with_cross_project_access_spec.rb
@@ -128,7 +128,7 @@ describe FinderWithCrossProjectAccess do
end
end
- context '.finder_model' do
+ describe '.finder_model' do
it 'is set correctly' do
expect(finder_class.finder_model).to eq(Project)
end
diff --git a/spec/finders/projects/prometheus/alerts_finder_spec.rb b/spec/finders/projects/prometheus/alerts_finder_spec.rb
new file mode 100644
index 00000000000..bb59e77cca8
--- /dev/null
+++ b/spec/finders/projects/prometheus/alerts_finder_spec.rb
@@ -0,0 +1,169 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Prometheus::AlertsFinder do
+ let(:finder) { described_class.new(params) }
+ let(:params) { {} }
+
+ describe 'with params' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:other_project) { create(:project) }
+ let_it_be(:other_env) { create(:environment, project: other_project) }
+ let_it_be(:production) { create(:environment, project: project) }
+ let_it_be(:staging) { create(:environment, project: project) }
+ let_it_be(:alert) { create_alert(project, production) }
+ let_it_be(:alert2) { create_alert(project, production) }
+ let_it_be(:stg_alert) { create_alert(project, staging) }
+ let_it_be(:other_alert) { create_alert(other_project, other_env) }
+
+ describe '#execute' do
+ subject { finder.execute }
+
+ context 'with project' do
+ before do
+ params[:project] = project
+ end
+
+ it { is_expected.to eq([alert, alert2, stg_alert]) }
+
+ context 'with matching metric' do
+ before do
+ params[:metric] = alert.prometheus_metric
+ end
+
+ it { is_expected.to eq([alert]) }
+ end
+
+ context 'with matching metric id' do
+ before do
+ params[:metric] = alert.prometheus_metric_id
+ end
+
+ it { is_expected.to eq([alert]) }
+ end
+
+ context 'with project non-specific metric' do
+ before do
+ params[:metric] = other_alert.prometheus_metric
+ end
+
+ it { is_expected.to be_empty }
+ end
+ end
+
+ context 'with environment' do
+ before do
+ params[:environment] = production
+ end
+
+ it { is_expected.to eq([alert, alert2]) }
+
+ context 'with matching metric' do
+ before do
+ params[:metric] = alert.prometheus_metric
+ end
+
+ it { is_expected.to eq([alert]) }
+ end
+
+ context 'with environment non-specific metric' do
+ before do
+ params[:metric] = stg_alert.prometheus_metric
+ end
+
+ it { is_expected.to be_empty }
+ end
+ end
+
+ context 'with matching project and environment' do
+ before do
+ params[:project] = project
+ params[:environment] = production
+ end
+
+ it { is_expected.to eq([alert, alert2]) }
+
+ context 'with matching metric' do
+ before do
+ params[:metric] = alert.prometheus_metric
+ end
+
+ it { is_expected.to eq([alert]) }
+ end
+
+ context 'with environment non-specific metric' do
+ before do
+ params[:metric] = stg_alert.prometheus_metric
+ end
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with matching id' do
+ before do
+ params[:id] = alert.id
+ end
+
+ it { is_expected.to eq([alert]) }
+ end
+
+ context 'with a nil id' do
+ before do
+ params[:id] = nil
+ end
+
+ it { is_expected.to eq([alert, alert2]) }
+ end
+ end
+
+ context 'with non-matching project-environment pair' do
+ before do
+ params[:project] = project
+ params[:environment] = other_env
+ end
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with id' do
+ before do
+ params[:id] = alert.id
+ end
+
+ it { is_expected.to eq([alert]) }
+ end
+
+ context 'with multiple ids' do
+ before do
+ params[:id] = [alert.id, other_alert.id]
+ end
+
+ it { is_expected.to eq([alert, other_alert]) }
+ end
+
+ context 'with non-matching id' do
+ before do
+ params[:id] = -5
+ end
+
+ it { is_expected.to be_empty }
+ end
+ end
+
+ private
+
+ def create_alert(project, environment)
+ create(:prometheus_alert, project: project, environment: environment)
+ end
+ end
+
+ describe 'without params' do
+ subject { finder }
+
+ it 'raises an error' do
+ expect { subject }
+ .to raise_error(ArgumentError, 'Please provide one or more of the following params: :project, :environment, :id')
+ end
+ end
+end
diff --git a/spec/finders/protected_branches_finder_spec.rb b/spec/finders/protected_branches_finder_spec.rb
new file mode 100644
index 00000000000..e6a2cf4577c
--- /dev/null
+++ b/spec/finders/protected_branches_finder_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ProtectedBranchesFinder do
+ let(:project) { create(:project) }
+ let!(:protected_branch) { create(:protected_branch, project: project) }
+ let!(:another_protected_branch) { create(:protected_branch, project: project) }
+ let!(:other_protected_branch) { create(:protected_branch) }
+ let(:params) { {} }
+
+ describe '#execute' do
+ subject { described_class.new(project, params).execute }
+
+ it 'returns all protected branches of project by default' do
+ expect(subject).to match_array([protected_branch, another_protected_branch])
+ end
+
+ context 'when search param is present' do
+ let(:params) { { search: protected_branch.name } }
+
+ it 'filters by search param' do
+ expect(subject).to eq([protected_branch])
+ end
+ end
+
+ context 'when there are more protected branches than the limit' do
+ before do
+ stub_const("#{described_class}::LIMIT", 1)
+ end
+
+ it 'returns limited protected branches of project' do
+ expect(subject).to eq([another_protected_branch])
+ end
+ end
+ end
+end
diff --git a/spec/frontend/environments/environment_external_url_spec.js b/spec/frontend/environments/environment_external_url_spec.js
new file mode 100644
index 00000000000..9997ea94941
--- /dev/null
+++ b/spec/frontend/environments/environment_external_url_spec.js
@@ -0,0 +1,16 @@
+import { shallowMount } from '@vue/test-utils';
+import ExternalUrlComp from '~/environments/components/environment_external_url.vue';
+
+describe('External URL Component', () => {
+ let wrapper;
+ const externalUrl = 'https://gitlab.com';
+
+ beforeEach(() => {
+ wrapper = shallowMount(ExternalUrlComp, { propsData: { externalUrl } });
+ });
+
+ it('should link to the provided externalUrl prop', () => {
+ expect(wrapper.attributes('href')).toEqual(externalUrl);
+ expect(wrapper.find('a').exists()).toBe(true);
+ });
+});
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 7f988c60817..63aa41bbad5 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -258,7 +258,7 @@ describe DiffHelper do
end
end
- context '#render_overflow_warning?' do
+ describe '#render_overflow_warning?' do
let(:diffs_collection) { instance_double(Gitlab::Diff::FileCollection::MergeRequestDiff, raw_diff_files: diff_files) }
let(:diff_files) { Gitlab::Git::DiffCollection.new(files) }
let(:safe_file) { { too_large: false, diff: '' } }
@@ -303,7 +303,7 @@ describe DiffHelper do
end
end
- context '#diff_file_path_text' do
+ describe '#diff_file_path_text' do
it 'returns full path by default' do
expect(diff_file_path_text(diff_file)).to eq(diff_file.new_path)
end
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
index 8d7572c5b5f..a3e879a3f39 100644
--- a/spec/helpers/nav_helper_spec.rb
+++ b/spec/helpers/nav_helper_spec.rb
@@ -106,13 +106,13 @@ describe NavHelper, :do_not_mock_admin_mode do
end
end
- context '.admin_monitoring_nav_links' do
+ describe '.admin_monitoring_nav_links' do
subject { helper.admin_monitoring_nav_links }
it { is_expected.to all(be_a(String)) }
end
- context '.group_issues_sub_menu_items' do
+ describe '.group_issues_sub_menu_items' do
subject { helper.group_issues_sub_menu_items }
it { is_expected.to all(be_a(String)) }
diff --git a/spec/helpers/sourcegraph_helper_spec.rb b/spec/helpers/sourcegraph_helper_spec.rb
index 830bbb3129f..3e8486a5632 100644
--- a/spec/helpers/sourcegraph_helper_spec.rb
+++ b/spec/helpers/sourcegraph_helper_spec.rb
@@ -34,7 +34,7 @@ describe SourcegraphHelper do
end
end
- context '#sourcegraph_experimental_message' do
+ describe '#sourcegraph_experimental_message' do
let(:feature_conditional) { false }
let(:public_only) { false }
diff --git a/spec/javascripts/environments/environment_external_url_spec.js b/spec/javascripts/environments/environment_external_url_spec.js
deleted file mode 100644
index 056d68a26e9..00000000000
--- a/spec/javascripts/environments/environment_external_url_spec.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import Vue from 'vue';
-import externalUrlComp from '~/environments/components/environment_external_url.vue';
-
-describe('External URL Component', () => {
- let ExternalUrlComponent;
-
- beforeEach(() => {
- ExternalUrlComponent = Vue.extend(externalUrlComp);
- });
-
- it('should link to the provided externalUrl prop', () => {
- const externalURL = 'https://gitlab.com';
- const component = new ExternalUrlComponent({
- propsData: {
- externalUrl: externalURL,
- },
- }).$mount();
-
- expect(component.$el.getAttribute('href')).toEqual(externalURL);
- expect(component.$el.querySelector('fa-external-link')).toBeDefined();
- });
-});
diff --git a/spec/lib/container_registry/registry_spec.rb b/spec/lib/container_registry/registry_spec.rb
index 7cf70a1f562..e509566fae8 100644
--- a/spec/lib/container_registry/registry_spec.rb
+++ b/spec/lib/container_registry/registry_spec.rb
@@ -14,7 +14,7 @@ describe ContainerRegistry::Registry do
it { expect(subject).not_to be_nil }
- context '#path' do
+ describe '#path' do
subject { registry.path }
context 'path from URL' do
diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb
index 9447112e4a8..085c73caa97 100644
--- a/spec/lib/container_registry/tag_spec.rb
+++ b/spec/lib/container_registry/tag_spec.rb
@@ -70,26 +70,26 @@ describe ContainerRegistry::Tag do
headers: { 'Content-Type' => 'application/vnd.docker.distribution.manifest.v1+prettyjws' })
end
- context '#layers' do
+ describe '#layers' do
subject { tag.layers }
it { expect(subject.length).to eq(1) }
end
- context '#total_size' do
+ describe '#total_size' do
subject { tag.total_size }
it { is_expected.to be_nil }
end
context 'config processing' do
- context '#config' do
+ describe '#config' do
subject { tag.config }
it { is_expected.to be_nil }
end
- context '#created_at' do
+ describe '#created_at' do
subject { tag.created_at }
it { is_expected.to be_nil }
@@ -113,7 +113,7 @@ describe ContainerRegistry::Tag do
body: File.read(Rails.root + 'spec/fixtures/container_registry/config_blob_helm.json'))
end
- context '#created_at' do
+ describe '#created_at' do
subject { tag.created_at }
it { is_expected.to be_nil }
@@ -130,13 +130,13 @@ describe ContainerRegistry::Tag do
headers: { 'Content-Type' => 'application/vnd.docker.distribution.manifest.v2+json' })
end
- context '#layers' do
+ describe '#layers' do
subject { tag.layers }
it { expect(subject.length).to eq(1) }
end
- context '#total_size' do
+ describe '#total_size' do
subject { tag.total_size }
it { is_expected.to eq(2319870) }
@@ -144,13 +144,13 @@ describe ContainerRegistry::Tag do
context 'config processing' do
shared_examples 'a processable' do
- context '#config' do
+ describe '#config' do
subject { tag.config }
it { is_expected.not_to be_nil }
end
- context '#created_at' do
+ describe '#created_at' do
subject { tag.created_at }
it { is_expected.not_to be_nil }
diff --git a/spec/lib/gitlab/alerting/alert_spec.rb b/spec/lib/gitlab/alerting/alert_spec.rb
new file mode 100644
index 00000000000..90e93d189e2
--- /dev/null
+++ b/spec/lib/gitlab/alerting/alert_spec.rb
@@ -0,0 +1,226 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Alerting::Alert do
+ let_it_be(:project) { create(:project) }
+
+ let(:alert) { build(:alerting_alert, project: project, payload: payload) }
+ let(:payload) { {} }
+
+ shared_context 'gitlab alert' do
+ let(:gitlab_alert_id) { gitlab_alert.prometheus_metric_id.to_s }
+ let!(:gitlab_alert) { create(:prometheus_alert, project: project) }
+
+ before do
+ payload['labels'] = { 'gitlab_alert_id' => gitlab_alert_id }
+ end
+ end
+
+ shared_examples 'invalid alert' do
+ it 'is invalid' do
+ expect(alert).not_to be_valid
+ end
+ end
+
+ shared_examples 'parse payload' do |*pairs|
+ context 'without payload' do
+ it { is_expected.to be_nil }
+ end
+
+ pairs.each do |pair|
+ context "with #{pair}" do
+ let(:value) { 'some value' }
+
+ before do
+ section, name = pair.split('/')
+ payload[section] = { name => value }
+ end
+
+ it { is_expected.to eq(value) }
+ end
+ end
+ end
+
+ describe '#gitlab_alert' do
+ subject { alert.gitlab_alert }
+
+ context 'without payload' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with gitlab alert' do
+ include_context 'gitlab alert'
+
+ it { is_expected.to eq(gitlab_alert) }
+ end
+
+ context 'with unknown gitlab alert' do
+ include_context 'gitlab alert' do
+ let(:gitlab_alert_id) { 'unknown' }
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#title' do
+ subject { alert.title }
+
+ it_behaves_like 'parse payload',
+ 'annotations/title',
+ 'annotations/summary',
+ 'labels/alertname'
+
+ context 'with gitlab alert' do
+ include_context 'gitlab alert'
+
+ context 'with annotations/title' do
+ let(:value) { 'annotation title' }
+
+ before do
+ payload['annotations'] = { 'title' => value }
+ end
+
+ it { is_expected.to eq(gitlab_alert.title) }
+ end
+ end
+ end
+
+ describe '#description' do
+ subject { alert.description }
+
+ it_behaves_like 'parse payload', 'annotations/description'
+ end
+
+ describe '#annotations' do
+ subject { alert.annotations }
+
+ context 'without payload' do
+ it { is_expected.to eq([]) }
+ end
+
+ context 'with payload' do
+ before do
+ payload['annotations'] = { 'foo' => 'value1', 'bar' => 'value2' }
+ end
+
+ it 'parses annotations' do
+ expect(subject.size).to eq(2)
+ expect(subject.map(&:label)).to eq(%w[foo bar])
+ expect(subject.map(&:value)).to eq(%w[value1 value2])
+ end
+ end
+ end
+
+ describe '#environment' do
+ subject { alert.environment }
+
+ context 'without gitlab_alert' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with gitlab alert' do
+ include_context 'gitlab alert'
+
+ it { is_expected.to eq(gitlab_alert.environment) }
+ end
+ end
+
+ describe '#starts_at' do
+ subject { alert.starts_at }
+
+ context 'with empty startsAt' do
+ before do
+ payload['startsAt'] = nil
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'with invalid startsAt' do
+ before do
+ payload['startsAt'] = 'invalid'
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'with payload' do
+ let(:time) { Time.now.change(usec: 0) }
+
+ before do
+ payload['startsAt'] = time.rfc3339
+ end
+
+ it { is_expected.to eq(time) }
+ end
+ end
+
+ describe '#full_query' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { alert.full_query }
+
+ where(:generator_url, :expected_query) do
+ nil | nil
+ 'http://localhost' | nil
+ 'invalid url' | nil
+ 'http://localhost:9090/graph?g1.expr=vector%281%29' | nil
+ 'http://localhost:9090/graph?g0.expr=vector%281%29' | 'vector(1)'
+ end
+
+ with_them do
+ before do
+ payload['generatorURL'] = generator_url
+ end
+
+ it { is_expected.to eq(expected_query) }
+ end
+
+ context 'with gitlab alert' do
+ include_context 'gitlab alert'
+
+ before do
+ payload['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29'
+ end
+
+ it { is_expected.to eq(gitlab_alert.full_query) }
+ end
+ end
+
+ describe '#alert_markdown' do
+ subject { alert.alert_markdown }
+
+ it_behaves_like 'parse payload', 'annotations/gitlab_incident_markdown'
+ end
+
+ describe '#valid?' do
+ before do
+ payload.update(
+ 'annotations' => { 'title' => 'some title' },
+ 'startsAt' => Time.now.rfc3339
+ )
+ end
+
+ subject { alert }
+
+ it { is_expected.to be_valid }
+
+ context 'without project' do
+ # Redefine to prevent:
+ # project is a NilClass - rspec-set works with ActiveRecord models only
+ let(:alert) { build(:alerting_alert, project: nil, payload: payload) }
+
+ it { is_expected.not_to be_valid }
+ end
+
+ context 'without starts_at' do
+ before do
+ payload['startsAt'] = nil
+ end
+
+ it { is_expected.not_to be_valid }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb b/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
index 3605bac7dfc..10843a1435a 100644
--- a/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
@@ -18,7 +18,7 @@ describe Gitlab::Ci::Build::Rules::Rule::Clause::Exists do
before do
stub_const('Gitlab::Ci::Build::Rules::Rule::Clause::Exists::MAX_PATTERN_COMPARISONS', 2)
- expect(File).to receive(:fnmatch?).exactly(2).times.and_call_original
+ expect(File).to receive(:fnmatch?).twice.and_call_original
end
it { is_expected.to be_truthy }
diff --git a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb
index 795e8e51276..1b034656e7d 100644
--- a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb
+++ b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb
@@ -12,7 +12,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
stub_feature_flags(ci_enable_live_trace: true)
end
- context "#initialize" do
+ describe "#initialize" do
context 'when a chunk exists' do
before do
build.trace.set('ABC')
@@ -35,7 +35,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#seek" do
+ describe "#seek" do
subject { chunked_io.seek(pos, where) }
before do
@@ -66,7 +66,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#eof?" do
+ describe "#eof?" do
subject { chunked_io.eof? }
before do
@@ -90,7 +90,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#each_line" do
+ describe "#each_line" do
let(:string_io) { StringIO.new(sample_trace_raw) }
context 'when buffer size is smaller than file size' do
@@ -134,7 +134,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#read" do
+ describe "#read" do
subject { chunked_io.read(length) }
context 'when read the whole size' do
@@ -254,7 +254,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#readline" do
+ describe "#readline" do
subject { chunked_io.readline }
let(:string_io) { StringIO.new(sample_trace_raw) }
@@ -334,7 +334,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#write" do
+ describe "#write" do
subject { chunked_io.write(data) }
let(:data) { sample_trace_raw }
@@ -399,7 +399,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#truncate" do
+ describe "#truncate" do
let(:offset) { 10 }
context 'when data does not exist' do
@@ -432,7 +432,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do
end
end
- context "#destroy!" do
+ describe "#destroy!" do
subject { chunked_io.destroy! }
before do
diff --git a/spec/lib/gitlab/ci/trace/section_parser_spec.rb b/spec/lib/gitlab/ci/trace/section_parser_spec.rb
index 6e8504a1584..24ce4d34411 100644
--- a/spec/lib/gitlab/ci/trace/section_parser_spec.rb
+++ b/spec/lib/gitlab/ci/trace/section_parser_spec.rb
@@ -74,7 +74,7 @@ describe Gitlab::Ci::Trace::SectionParser do
let(:lines) { build_lines(trace) }
it 'must handle correctly byte positioning' do
- expect(subject).to receive(:find_next_marker).exactly(2).times.and_call_original
+ expect(subject).to receive(:find_next_marker).twice.and_call_original
subject.parse!
diff --git a/spec/lib/gitlab/cleanup/project_uploads_spec.rb b/spec/lib/gitlab/cleanup/project_uploads_spec.rb
index 5787cce7d20..d1e3a73686e 100644
--- a/spec/lib/gitlab/cleanup/project_uploads_spec.rb
+++ b/spec/lib/gitlab/cleanup/project_uploads_spec.rb
@@ -8,8 +8,8 @@ describe Gitlab::Cleanup::ProjectUploads do
let(:logger) { double(:logger) }
before do
- allow(logger).to receive(:info).at_least(1).times
- allow(logger).to receive(:debug).at_least(1).times
+ allow(logger).to receive(:info).at_least(:once)
+ allow(logger).to receive(:debug).at_least(:once)
end
describe '#run!' do
diff --git a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
index 1d404915617..bbbbf91bd44 100644
--- a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
+++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
@@ -19,7 +19,7 @@ describe Gitlab::ContentSecurityPolicy::ConfigLoader do
}
end
- context '.default_settings_hash' do
+ describe '.default_settings_hash' do
it 'returns empty defaults' do
settings = described_class.default_settings_hash
@@ -33,7 +33,7 @@ describe Gitlab::ContentSecurityPolicy::ConfigLoader do
end
end
- context '#load' do
+ describe '#load' do
subject { described_class.new(csp_config[:directives]) }
def expected_config(directive)
diff --git a/spec/lib/gitlab/danger/teammate_spec.rb b/spec/lib/gitlab/danger/teammate_spec.rb
index bf6152ff3c2..570f4bd27cc 100644
--- a/spec/lib/gitlab/danger/teammate_spec.rb
+++ b/spec/lib/gitlab/danger/teammate_spec.rb
@@ -176,7 +176,7 @@ describe Gitlab::Danger::Teammate do
it 'returns true if request fails' do
expect(Gitlab::Danger::RequestHelper).to receive(:http_get_json)
- .exactly(2).times
+ .twice
.and_raise(Gitlab::Danger::RequestHelper::HTTPError.new)
expect(subject.available?).to be true
diff --git a/spec/lib/gitlab/database/count_spec.rb b/spec/lib/gitlab/database/count_spec.rb
index 71c25f23b6b..2469ce482e7 100644
--- a/spec/lib/gitlab/database/count_spec.rb
+++ b/spec/lib/gitlab/database/count_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::Database::Count do
let(:models) { [Project, Identity] }
- context '.approximate_counts' do
+ describe '.approximate_counts' do
context 'fallbacks' do
subject { described_class.approximate_counts(models, strategies: strategies) }
diff --git a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
index 1e9083950d0..300d7bb14b6 100644
--- a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
+++ b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
@@ -31,7 +31,7 @@ describe Gitlab::Git::RuggedImpl::UseRugged, :seed_helper do
Gitlab::GitalyClient.instance_variable_set(:@can_use_disk, {})
end
- context '#execute_rugged_call', :request_store do
+ describe '#execute_rugged_call', :request_store do
let(:args) { ['refs/heads/master', 1] }
before do
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 231bcb4150c..0831021b22b 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -757,7 +757,7 @@ describe Gitlab::GitAccess do
allow(project).to receive(:lfs_enabled?).and_return(true)
expect_next_instance_of(Gitlab::Checks::LfsIntegrity) do |instance|
- expect(instance).to receive(:objects_missing?).exactly(1).times
+ expect(instance).to receive(:objects_missing?).once
end
push_access_check
diff --git a/spec/lib/gitlab/git_ref_validator_spec.rb b/spec/lib/gitlab/git_ref_validator_spec.rb
index 1531317c514..28cc13f02de 100644
--- a/spec/lib/gitlab/git_ref_validator_spec.rb
+++ b/spec/lib/gitlab/git_ref_validator_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
describe Gitlab::GitRefValidator do
using RSpec::Parameterized::TableSyntax
- context '.validate' do
+ describe '.validate' do
it { expect(described_class.validate('feature/new')).to be true }
it { expect(described_class.validate('implement_@all')).to be true }
it { expect(described_class.validate('my_new_feature')).to be true }
@@ -37,7 +37,7 @@ describe Gitlab::GitRefValidator do
it { expect(described_class.validate("\xA0\u0000\xB0")).to be false }
end
- context '.validate_merge_request_branch' do
+ describe '.validate_merge_request_branch' do
it { expect(described_class.validate_merge_request_branch('HEAD')).to be true }
it { expect(described_class.validate_merge_request_branch('feature/new')).to be true }
it { expect(described_class.validate_merge_request_branch('implement_@all')).to be true }
diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb
index fac2dbfab71..c7b9775f642 100644
--- a/spec/lib/gitlab/gpg_spec.rb
+++ b/spec/lib/gitlab/gpg_spec.rb
@@ -215,8 +215,8 @@ describe Gitlab::Gpg do
end
it 'tries at least 2 times to remove the tmp dir before raising', :aggregate_failures do
- expect(Retriable).to receive(:sleep).at_least(2).times
- expect(FileUtils).to receive(:remove_entry).with(tmp_dir).at_least(2).times.and_raise('Deletion failed')
+ expect(Retriable).to receive(:sleep).at_least(:twice)
+ expect(FileUtils).to receive(:remove_entry).with(tmp_dir).at_least(:twice).and_raise('Deletion failed')
expect { described_class.using_tmp_keychain { } }.to raise_error(described_class::CleanupError)
end
diff --git a/spec/lib/gitlab/legacy_github_import/importer_spec.rb b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
index c6ee0a3c094..7fef763f64d 100644
--- a/spec/lib/gitlab/legacy_github_import/importer_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
@@ -205,7 +205,7 @@ describe Gitlab::LegacyGithubImport::Importer do
let(:gh_pull_request) { Gitlab::LegacyGithubImport::PullRequestFormatter.new(project, closed_pull_request) }
it 'does remove branches' do
- expect(subject).to receive(:remove_branch).at_least(2).times
+ expect(subject).to receive(:remove_branch).at_least(:twice)
subject.send(:clean_up_restored_branches, gh_pull_request)
end
end
diff --git a/spec/lib/gitlab/private_commit_email_spec.rb b/spec/lib/gitlab/private_commit_email_spec.rb
index 10bf624bbdd..7b7a0f7c0ca 100644
--- a/spec/lib/gitlab/private_commit_email_spec.rb
+++ b/spec/lib/gitlab/private_commit_email_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::PrivateCommitEmail do
let(:valid_email) { "#{id}-foo@#{hostname}" }
let(:invalid_email) { "#{id}-foo@users.noreply.bar.com" }
- context '.regex' do
+ describe '.regex' do
subject { described_class.regex }
it { is_expected.to match("1-foo@#{hostname}") }
@@ -18,7 +18,7 @@ describe Gitlab::PrivateCommitEmail do
it { is_expected.not_to match('foobar@gitlab.com') }
end
- context '.user_id_for_email' do
+ describe '.user_id_for_email' do
it 'parses user id from email' do
expect(described_class.user_id_for_email(valid_email)).to eq(id)
end
@@ -28,7 +28,7 @@ describe Gitlab::PrivateCommitEmail do
end
end
- context '.user_ids_for_email' do
+ describe '.user_ids_for_email' do
it 'returns deduplicated user IDs for each valid email' do
result = described_class.user_ids_for_emails([valid_email, valid_email, invalid_email])
@@ -41,7 +41,7 @@ describe Gitlab::PrivateCommitEmail do
end
end
- context '.for_user' do
+ describe '.for_user' do
it 'returns email in the format id-username@hostname' do
user = create(:user)
diff --git a/spec/lib/gitlab/rugged_instrumentation_spec.rb b/spec/lib/gitlab/rugged_instrumentation_spec.rb
index 4dcc8ae514a..64c0ce1b65e 100644
--- a/spec/lib/gitlab/rugged_instrumentation_spec.rb
+++ b/spec/lib/gitlab/rugged_instrumentation_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::RuggedInstrumentation, :request_store do
end
end
- context '.increment_query_count' do
+ describe '.increment_query_count' do
it 'tracks query counts' do
expect(subject.query_count).to eq(0)
diff --git a/spec/lib/gitlab/sanitizers/exif_spec.rb b/spec/lib/gitlab/sanitizers/exif_spec.rb
index 11e430e0be4..f0b733817b3 100644
--- a/spec/lib/gitlab/sanitizers/exif_spec.rb
+++ b/spec/lib/gitlab/sanitizers/exif_spec.rb
@@ -30,7 +30,7 @@ describe Gitlab::Sanitizers::Exif do
end
it 'processes only uploads created since specified date' do
- expect(sanitizer).to receive(:clean).exactly(2).times
+ expect(sanitizer).to receive(:clean).twice
sanitizer.batch_clean(since: 2.days.ago)
end
diff --git a/spec/lib/omni_auth/strategies/jwt_spec.rb b/spec/lib/omni_auth/strategies/jwt_spec.rb
index a8c565aa705..f2b682850e3 100644
--- a/spec/lib/omni_auth/strategies/jwt_spec.rb
+++ b/spec/lib/omni_auth/strategies/jwt_spec.rb
@@ -6,7 +6,7 @@ describe OmniAuth::Strategies::Jwt do
include Rack::Test::Methods
include DeviseHelpers
- context '#decoded' do
+ describe '#decoded' do
subject { described_class.new({}) }
let(:timestamp) { Time.now.to_i }
diff --git a/spec/lib/safe_zip/entry_spec.rb b/spec/lib/safe_zip/entry_spec.rb
index 0974f732188..be3d46917ee 100644
--- a/spec/lib/safe_zip/entry_spec.rb
+++ b/spec/lib/safe_zip/entry_spec.rb
@@ -25,13 +25,13 @@ describe SafeZip::Entry do
FileUtils.remove_entry_secure(target_path)
end
- context '#path_dir' do
+ describe '#path_dir' do
subject { entry.path_dir }
it { is_expected.to eq(target_path + '/public/folder') }
end
- context '#exist?' do
+ describe '#exist?' do
subject { entry.exist? }
context 'when entry does not exist' do
diff --git a/spec/lib/safe_zip/extract_spec.rb b/spec/lib/safe_zip/extract_spec.rb
index 3b8c64c1c9f..d388135c3fb 100644
--- a/spec/lib/safe_zip/extract_spec.rb
+++ b/spec/lib/safe_zip/extract_spec.rb
@@ -12,7 +12,7 @@ describe SafeZip::Extract do
FileUtils.remove_entry_secure(target_path)
end
- context '#extract' do
+ describe '#extract' do
subject { object.extract(directories: directories, to: target_path) }
shared_examples 'extracts archive' do |param|
diff --git a/spec/models/badge_spec.rb b/spec/models/badge_spec.rb
index c661f5384ea..60ae579eb03 100644
--- a/spec/models/badge_spec.rb
+++ b/spec/models/badge_spec.rb
@@ -81,13 +81,13 @@ describe Badge do
let(:badge) { build(:badge, link_url: placeholder_url, image_url: placeholder_url) }
let!(:project) { create(:project) }
- context '#rendered_link_url' do
+ describe '#rendered_link_url' do
let(:method) { :link_url }
it_behaves_like 'rendered_links'
end
- context '#rendered_image_url' do
+ describe '#rendered_image_url' do
let(:method) { :image_url }
it_behaves_like 'rendered_links'
diff --git a/spec/models/badges/project_badge_spec.rb b/spec/models/badges/project_badge_spec.rb
index d41c5cf2ca1..c0e85d3de87 100644
--- a/spec/models/badges/project_badge_spec.rb
+++ b/spec/models/badges/project_badge_spec.rb
@@ -30,13 +30,13 @@ describe ProjectBadge do
let(:badge) { build(:project_badge, link_url: placeholder_url, image_url: placeholder_url) }
let!(:project) { badge.project }
- context '#rendered_link_url' do
+ describe '#rendered_link_url' do
let(:method) { :link_url }
it_behaves_like 'rendered_links'
end
- context '#rendered_image_url' do
+ describe '#rendered_image_url' do
let(:method) { :image_url }
it_behaves_like 'rendered_links'
diff --git a/spec/models/ci/artifact_blob_spec.rb b/spec/models/ci/artifact_blob_spec.rb
index 8a66b55cc15..99983686670 100644
--- a/spec/models/ci/artifact_blob_spec.rb
+++ b/spec/models/ci/artifact_blob_spec.rb
@@ -51,7 +51,7 @@ describe Ci::ArtifactBlob do
allow(Gitlab.config.pages).to receive(:artifacts_server).and_return(true)
end
- context '.gif extension' do
+ describe '.gif extension' do
it 'returns nil' do
expect(subject.external_url(build.project, build)).to be_nil
end
diff --git a/spec/models/ci/persistent_ref_spec.rb b/spec/models/ci/persistent_ref_spec.rb
index ece478fdd36..4cece0664cf 100644
--- a/spec/models/ci/persistent_ref_spec.rb
+++ b/spec/models/ci/persistent_ref_spec.rb
@@ -11,7 +11,7 @@ describe Ci::PersistentRef do
pipeline.succeed!
end
- context '#exist?' do
+ describe '#exist?' do
subject { pipeline.persistent_ref.exist? }
let(:pipeline) { create(:ci_pipeline, sha: sha, project: project) }
@@ -31,7 +31,7 @@ describe Ci::PersistentRef do
end
end
- context '#create' do
+ describe '#create' do
subject { pipeline.persistent_ref.create }
let(:pipeline) { create(:ci_pipeline, sha: sha, project: project) }
@@ -81,7 +81,7 @@ describe Ci::PersistentRef do
end
end
- context '#delete' do
+ describe '#delete' do
subject { pipeline.persistent_ref.delete }
let(:pipeline) { create(:ci_pipeline, sha: sha, project: project) }
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 5c9a03a26ec..3e494d19233 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -25,7 +25,7 @@ describe Ci::Runner do
end
end
- context '#exactly_one_group' do
+ describe '#exactly_one_group' do
let(:group) { create(:group) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
diff --git a/spec/models/concerns/avatarable_spec.rb b/spec/models/concerns/avatarable_spec.rb
index c750be6b75c..100953549ea 100644
--- a/spec/models/concerns/avatarable_spec.rb
+++ b/spec/models/concerns/avatarable_spec.rb
@@ -48,14 +48,14 @@ describe Avatarable do
end
it 'calls local_url twice for path and URLs' do
- expect(project.avatar).to receive(:local_url).exactly(2).times.and_call_original
+ expect(project.avatar).to receive(:local_url).twice.and_call_original
expect(project.avatar_path(only_path: true)).to eq(avatar_path)
expect(project.avatar_path(only_path: false)).to eq(avatar_url)
end
it 'calls local_url twice for different sizes' do
- expect(project.avatar).to receive(:local_url).exactly(2).times.and_call_original
+ expect(project.avatar).to receive(:local_url).twice.and_call_original
expect(project.avatar_path).to eq(avatar_path)
expect(project.avatar_path(size: 40)).to eq(avatar_path + "?width=40")
@@ -64,7 +64,7 @@ describe Avatarable do
it 'handles unpersisted objects' do
new_project = build(:project, :with_avatar)
path = [relative_url_root, new_project.avatar.local_url].join
- expect(new_project.avatar).to receive(:local_url).exactly(2).times.and_call_original
+ expect(new_project.avatar).to receive(:local_url).twice.and_call_original
2.times do
expect(new_project.avatar_path).to eq(path)
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index f78a089bc2e..c891fdcb6b5 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -58,7 +58,7 @@ describe Group, 'Routable' do
end
end
- context '.find_by_full_path' do
+ describe '.find_by_full_path' do
let!(:nested_group) { create(:group, parent: group) }
context 'without any redirect routes' do
diff --git a/spec/models/concerns/triggerable_hooks_spec.rb b/spec/models/concerns/triggerable_hooks_spec.rb
index ac1bc51d950..10a6c1aa821 100644
--- a/spec/models/concerns/triggerable_hooks_spec.rb
+++ b/spec/models/concerns/triggerable_hooks_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe TriggerableHooks do
TestableHook.create!(url: 'http://example2.com', push_events: true)
filter1 = double(:filter1)
filter2 = double(:filter2)
- allow(ActiveHookFilter).to receive(:new).exactly(2).times.and_return(filter1, filter2)
+ allow(ActiveHookFilter).to receive(:new).twice.and_return(filter1, filter2)
expect(filter1).to receive(:matches?).and_return(true)
expect(filter2).to receive(:matches?).and_return(false)
diff --git a/spec/models/deployment_metrics_spec.rb b/spec/models/deployment_metrics_spec.rb
index 32c04e15b73..5a4ae0bbe79 100644
--- a/spec/models/deployment_metrics_spec.rb
+++ b/spec/models/deployment_metrics_spec.rb
@@ -87,7 +87,7 @@ describe DeploymentMetrics do
expect(prometheus_adapter).to receive(:query).with(:deployment, deployment).and_return(simple_metrics)
end
- it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
+ it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.finished_at.to_i })) }
end
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 0c1b259d6bf..c1beef0b759 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -495,7 +495,7 @@ describe Deployment do
end
end
- context '#update_status' do
+ describe '#update_status' do
let(:deploy) { create(:deployment, status: :running) }
it 'changes the status' do
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 5aa74134692..c0501fb16c6 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -359,7 +359,7 @@ describe Issue do
allow(subject.project).to receive(:repository).and_return(repository)
end
- context '#to_branch_name does not exists' do
+ describe '#to_branch_name does not exists' do
before do
allow(repository).to receive(:branch_exists?).and_return(false)
end
@@ -369,7 +369,7 @@ describe Issue do
end
end
- context '#to_branch_name exists not ending with -index' do
+ describe '#to_branch_name exists not ending with -index' do
before do
allow(repository).to receive(:branch_exists?).and_return(true)
allow(repository).to receive(:branch_exists?).with(/#{subject.to_branch_name}-\d/).and_return(false)
@@ -380,7 +380,7 @@ describe Issue do
end
end
- context '#to_branch_name exists ending with -index' do
+ describe '#to_branch_name exists ending with -index' do
before do
allow(repository).to receive(:branch_exists?).and_return(true)
allow(repository).to receive(:branch_exists?).with("#{subject.to_branch_name}-3").and_return(false)
diff --git a/spec/models/notification_recipient_spec.rb b/spec/models/notification_recipient_spec.rb
index 2ba53818e54..f6a36dbb3fc 100644
--- a/spec/models/notification_recipient_spec.rb
+++ b/spec/models/notification_recipient_spec.rb
@@ -80,7 +80,7 @@ describe NotificationRecipient do
end
end
- context '#notification_setting' do
+ describe '#notification_setting' do
context 'for child groups' do
let!(:moved_group) { create(:group) }
let(:group) { create(:group) }
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index 65d227a17f9..1b946278790 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -148,7 +148,7 @@ describe BambooService, :use_clean_rails_memory_store_caching do
end
shared_examples 'reactive cache calculation' do
- context '#build_page' do
+ describe '#build_page' do
subject { service.calculate_reactive_cache('123', 'unused')[:build_page] }
it 'returns a specific URL when status is 500' do
@@ -180,7 +180,7 @@ describe BambooService, :use_clean_rails_memory_store_caching do
end
end
- context '#commit_status' do
+ describe '#commit_status' do
subject { service.calculate_reactive_cache('123', 'unused')[:commit_status] }
it 'sets commit status to :error when status is 500' do
diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index ca196069055..c622b7706c6 100644
--- a/spec/models/project_services/buildkite_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -83,7 +83,7 @@ describe BuildkiteService, :use_clean_rails_memory_store_caching do
end
describe '#calculate_reactive_cache' do
- context '#commit_status' do
+ describe '#commit_status' do
subject { service.calculate_reactive_cache('123', 'unused')[:commit_status] }
it 'sets commit status to :error when status is 500' 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 d3adc62c38e..c4d10be8331 100644
--- a/spec/models/project_services/chat_message/issue_message_spec.rb
+++ b/spec/models/project_services/chat_message/issue_message_spec.rb
@@ -31,7 +31,7 @@ describe ChatMessage::IssueMessage do
context 'without markdown' do
let(:color) { '#C95823' }
- context '#initialize' do
+ describe '#initialize' do
before do
args[:object_attributes][:description] = nil
end
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index a771d1bf27f..0639a4c1f23 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -86,7 +86,7 @@ describe DroneCiService, :use_clean_rails_memory_store_caching do
describe '#calculate_reactive_cache' do
include_context :drone_ci_service
- context '#commit_status' do
+ describe '#commit_status' do
subject { drone.calculate_reactive_cache(sha, branch)[:commit_status] }
it 'sets commit status to :error when status is 500' do
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index a1bd0855708..ae6e93cfe3a 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -352,7 +352,7 @@ describe HipchatService do
end
end
- context "#message_options" do
+ describe "#message_options" do
it "is set to the defaults" do
expect(hipchat.__send__(:message_options)).to eq({ notify: false, color: 'yellow' })
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index c573bf7793a..832c19adf1d 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -152,7 +152,7 @@ describe JiraService do
end
end
- context '#update' do
+ describe '#update' do
context 'basic update' do
let(:new_username) { 'new_username' }
let(:new_url) { 'http://jira-new.example.com' }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index fdcee973fa7..ae4db1c2158 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -4966,7 +4966,7 @@ describe Project do
end
end
- context '#members_among' do
+ describe '#members_among' do
let(:users) { create_list(:user, 3) }
set(:group) { create(:group) }
@@ -5507,6 +5507,18 @@ describe Project do
end
end
+ describe '#limited_protected_branches' do
+ let(:project) { create(:project) }
+ let!(:protected_branch) { create(:protected_branch, project: project) }
+ let!(:another_protected_branch) { create(:protected_branch, project: project) }
+
+ subject { project.limited_protected_branches(1) }
+
+ it 'returns limited number of protected branches based on specified limit' do
+ expect(subject).to eq([another_protected_branch])
+ end
+ end
+
def rugged_config
rugged_repo(project.repository).config
end
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index 267434a4148..7f8a60dafa8 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -220,4 +220,32 @@ describe ProtectedBranch do
end
end
end
+
+ describe '.by_name' do
+ let!(:protected_branch) { create(:protected_branch, name: 'master') }
+ let!(:another_protected_branch) { create(:protected_branch, name: 'stable') }
+
+ it 'returns protected branches with a matching name' do
+ expect(described_class.by_name(protected_branch.name))
+ .to eq([protected_branch])
+ end
+
+ it 'returns protected branches with a partially matching name' do
+ expect(described_class.by_name(protected_branch.name[0..2]))
+ .to eq([protected_branch])
+ end
+
+ it 'returns protected branches with a matching name regardless of the casing' do
+ expect(described_class.by_name(protected_branch.name.upcase))
+ .to eq([protected_branch])
+ end
+
+ it 'returns nothing when nothing matches' do
+ expect(described_class.by_name('unknown')).to be_empty
+ end
+
+ it 'return nothing when query is blank' do
+ expect(described_class.by_name('')).to be_empty
+ end
+ end
end
diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb
index 79d45da8a1e..f5e718e0e09 100644
--- a/spec/models/remote_mirror_spec.rb
+++ b/spec/models/remote_mirror_spec.rb
@@ -227,7 +227,7 @@ describe RemoteMirror, :mailer do
end
end
- context '#sync' do
+ describe '#sync' do
let(:remote_mirror) { create(:project, :repository, :remote_mirror).remote_mirrors.first }
around do |example|
@@ -297,7 +297,7 @@ describe RemoteMirror, :mailer do
end
end
- context '#ensure_remote!' do
+ describe '#ensure_remote!' do
let(:remote_mirror) { create(:project, :repository, :remote_mirror).remote_mirrors.first }
let(:project) { remote_mirror.project }
let(:repository) { project.repository }
@@ -321,7 +321,7 @@ describe RemoteMirror, :mailer do
end
end
- context '#url=' do
+ describe '#url=' do
let(:remote_mirror) { create(:project, :repository, :remote_mirror).remote_mirrors.first }
it 'resets all the columns when URL changes' do
@@ -340,7 +340,7 @@ describe RemoteMirror, :mailer do
end
end
- context '#updated_since?' do
+ describe '#updated_since?' do
let(:remote_mirror) { create(:project, :repository, :remote_mirror).remote_mirrors.first }
let(:timestamp) { Time.now - 5.minutes }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index d441f54a0fb..ac001ec3118 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -681,7 +681,7 @@ describe User, :do_not_mock_admin_mode do
end
describe 'before save hook' do
- context '#default_private_profile_to_false' do
+ describe '#default_private_profile_to_false' do
let(:user) { create(:user, private_profile: true) }
it 'converts nil to false' do
@@ -3161,7 +3161,7 @@ describe User, :do_not_mock_admin_mode do
end
end
- context '.active' do
+ describe '.active' do
before do
described_class.ghost
create(:user, name: 'user', state: 'active')
@@ -3181,7 +3181,7 @@ describe User, :do_not_mock_admin_mode do
end
end
- context '#invalidate_issue_cache_counts' do
+ describe '#invalidate_issue_cache_counts' do
let(:user) { build_stubbed(:user) }
it 'invalidates cache for issue counter' do
@@ -3195,7 +3195,7 @@ describe User, :do_not_mock_admin_mode do
end
end
- context '#invalidate_merge_request_cache_counts' do
+ describe '#invalidate_merge_request_cache_counts' do
let(:user) { build_stubbed(:user) }
it 'invalidates cache for Merge Request counter' do
@@ -3209,7 +3209,7 @@ describe User, :do_not_mock_admin_mode do
end
end
- context '#invalidate_personal_projects_count' do
+ describe '#invalidate_personal_projects_count' do
let(:user) { build_stubbed(:user) }
it 'invalidates cache for personal projects counter' do
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index a7c28519c5a..166620a927d 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -44,7 +44,7 @@ describe WikiPage do
WikiDirectory.new('dir_2', pages)
end
- context "#list_pages" do
+ describe "#list_pages" do
context 'sort by title' do
let(:grouped_entries) { described_class.group_by_directory(wiki.list_pages) }
let(:expected_grouped_entries) { [dir_1_1, dir_1, page_dir_2, dir_2, page_1, page_6] }
diff --git a/spec/presenters/projects/prometheus/alert_presenter_spec.rb b/spec/presenters/projects/prometheus/alert_presenter_spec.rb
new file mode 100644
index 00000000000..fc6ddcbfe02
--- /dev/null
+++ b/spec/presenters/projects/prometheus/alert_presenter_spec.rb
@@ -0,0 +1,235 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Prometheus::AlertPresenter do
+ let_it_be(:project) { create(:project) }
+
+ let(:presenter) { described_class.new(alert) }
+ let(:payload) { {} }
+ let(:alert) { create(:alerting_alert, project: project, payload: payload) }
+
+ describe '#project_full_path' do
+ subject { presenter.project_full_path }
+
+ it { is_expected.to eq(project.full_path) }
+ end
+
+ describe '#starts_at' do
+ subject { presenter.starts_at }
+
+ before do
+ payload['startsAt'] = starts_at
+ end
+
+ context 'with valid datetime' do
+ let(:datetime) { Time.now }
+ let(:starts_at) { datetime.rfc3339 }
+
+ it { is_expected.to eq(datetime.rfc3339) }
+ end
+
+ context 'with invalid datetime' do
+ let(:starts_at) { 'invalid' }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#issue_summary_markdown' do
+ let(:markdown_line_break) { ' ' }
+
+ subject { presenter.issue_summary_markdown }
+
+ context 'without default payload' do
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ #### Summary
+
+ **Start time:** #{presenter.starts_at}
+
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'with annotations' do
+ before do
+ payload['annotations'] = { 'title' => 'Alert Title', 'foo' => 'value1', 'bar' => 'value2' }
+ end
+
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ #### Summary
+
+ **Start time:** #{presenter.starts_at}
+
+ #### Alert Details
+
+ **foo:** value1#{markdown_line_break}
+ **bar:** value2
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'with full query' do
+ before do
+ payload['generatorURL'] = 'http://host?g0.expr=query'
+ end
+
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ #### Summary
+
+ **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **full_query:** `query`
+
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'with the Generic Alert parameters' do
+ let(:generic_alert_params) do
+ {
+ 'title' => 'The Generic Alert Title',
+ 'description' => 'The Generic Alert Description',
+ 'monitoring_tool' => 'monitoring_tool_name',
+ 'service' => 'service_name',
+ 'hosts' => ['http://localhost:3000', 'http://localhost:3001']
+ }
+ end
+
+ before do
+ payload['annotations'] = generic_alert_params
+ end
+
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ #### Summary
+
+ **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **Service:** service_name#{markdown_line_break}
+ **Monitoring tool:** monitoring_tool_name#{markdown_line_break}
+ **Hosts:** http://localhost:3000 http://localhost:3001
+
+ #### Alert Details
+
+ **description:** The Generic Alert Description
+ MARKDOWN
+ )
+ end
+
+ context 'when hosts is a string' do
+ before do
+ payload['annotations'] = { 'hosts' => 'http://localhost:3000' }
+ end
+
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ #### Summary
+
+ **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **Hosts:** http://localhost:3000
+
+ MARKDOWN
+ )
+ end
+ end
+ end
+ end
+
+ context 'with gitlab alert' do
+ let(:gitlab_alert) { create(:prometheus_alert, project: project) }
+ let(:metric_id) { gitlab_alert.prometheus_metric_id }
+
+ let(:alert) do
+ create(:alerting_alert, project: project, metric_id: metric_id)
+ end
+
+ describe '#full_title' do
+ let(:query_title) do
+ "#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold} for 5 minutes"
+ end
+
+ let(:expected_subject) do
+ "#{alert.environment.name}: #{query_title}"
+ end
+
+ subject { presenter.full_title }
+
+ it { is_expected.to eq(expected_subject) }
+ end
+
+ describe '#metric_query' do
+ subject { presenter.metric_query }
+
+ it { is_expected.to eq(gitlab_alert.full_query) }
+ end
+
+ describe '#environment_name' do
+ subject { presenter.environment_name }
+
+ it { is_expected.to eq(alert.environment.name) }
+ end
+
+ describe '#performance_dashboard_link' do
+ let(:expected_link) do
+ Gitlab::Routing.url_helpers
+ .metrics_project_environment_url(project, alert.environment)
+ end
+
+ subject { presenter.performance_dashboard_link }
+
+ it { is_expected.to eq(expected_link) }
+ end
+ end
+
+ context 'without gitlab alert' do
+ describe '#full_title' do
+ subject { presenter.full_title }
+
+ context 'with title' do
+ let(:title) { 'some title' }
+
+ before do
+ expect(alert).to receive(:title).and_return(title)
+ end
+
+ it { is_expected.to eq(title) }
+ end
+
+ context 'without title' do
+ it { is_expected.to eq('') }
+ end
+ end
+
+ describe '#metric_query' do
+ subject { presenter.metric_query }
+
+ it { is_expected.to be_nil }
+ end
+
+ describe '#environment_name' do
+ subject { presenter.environment_name }
+
+ it { is_expected.to be_nil }
+ end
+
+ describe '#performance_dashboard_link' do
+ let(:expected_link) do
+ Gitlab::Routing.url_helpers.metrics_project_environments_url(project)
+ end
+
+ subject { presenter.performance_dashboard_link }
+
+ it { is_expected.to eq(expected_link) }
+ end
+ end
+end
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index d0378278600..cad9329fcb8 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -46,7 +46,7 @@ describe 'GraphQL' do
end
it 'logs the exception in Sentry and continues with the request' do
- expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(1).times
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(:once)
expect(Gitlab::GraphqlLogger).to receive(:info)
post_graphql(query, variables: {})
diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb
index ef63902ffd7..f2a1b335589 100644
--- a/spec/requests/api/issues/get_group_issues_spec.rb
+++ b/spec/requests/api/issues/get_group_issues_spec.rb
@@ -689,7 +689,7 @@ describe API::Issues do
end
end
- context "#to_reference" do
+ describe "#to_reference" do
it 'exposes reference path in context of group' do
get api(base_url, user)
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index adfe865da90..245a8aa4905 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -781,7 +781,7 @@ describe API::MergeRequests do
it_behaves_like 'merge requests list'
end
- context "#to_reference" do
+ describe "#to_reference" do
it 'exposes reference path in context of group' do
get api("/groups/#{group.id}/merge_requests", user)
diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb
index 67ce704b3f3..8499a165d8b 100644
--- a/spec/requests/api/protected_branches_spec.rb
+++ b/spec/requests/api/protected_branches_spec.rb
@@ -12,18 +12,18 @@ describe API::ProtectedBranches do
end
describe "GET /projects/:id/protected_branches" do
+ let(:params) { {} }
let(:route) { "/projects/#{project.id}/protected_branches" }
shared_examples_for 'protected branches' do
it 'returns the protected branches' do
- get api(route, user), params: { per_page: 100 }
+ get api(route, user), params: params.merge(per_page: 100)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
protected_branch_names = json_response.map { |x| x['name'] }
- expected_branch_names = project.protected_branches.map { |x| x['name'] }
expect(protected_branch_names).to match_array(expected_branch_names)
end
end
@@ -33,7 +33,19 @@ describe API::ProtectedBranches do
project.add_maintainer(user)
end
- it_behaves_like 'protected branches'
+ context 'when search param is not present' do
+ it_behaves_like 'protected branches' do
+ let(:expected_branch_names) { project.protected_branches.map { |x| x['name'] } }
+ end
+ end
+
+ context 'when search param is present' do
+ it_behaves_like 'protected branches' do
+ let(:another_protected_branch) { create(:protected_branch, project: project, name: 'stable') }
+ let(:params) { { search: another_protected_branch.name } }
+ let(:expected_branch_names) { [another_protected_branch.name] }
+ end
+ end
end
context 'when authenticated as a guest' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 84e1f95828a..f6ff2020c79 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -778,6 +778,12 @@ describe API::Users do
expect(user.reload.external?).to be_truthy
end
+ it "private profile is false by default" do
+ put api("/users/#{user.id}", admin), params: {}
+
+ expect(user.reload.private_profile).to eq(false)
+ end
+
it "updates private profile" do
put api("/users/#{user.id}", admin), params: { private_profile: true }
@@ -785,14 +791,24 @@ describe API::Users do
expect(user.reload.private_profile).to eq(true)
end
- it "updates private profile when nil is given to false" do
- admin.update(private_profile: true)
+ it "updates private profile to false when nil is given" do
+ user.update(private_profile: true)
put api("/users/#{user.id}", admin), params: { private_profile: nil }
+ expect(response).to have_gitlab_http_status(200)
expect(user.reload.private_profile).to eq(false)
end
+ it "does not modify private profile when field is not provided" do
+ user.update(private_profile: true)
+
+ put api("/users/#{user.id}", admin), params: {}
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(user.reload.private_profile).to eq(true)
+ end
+
it "does not update admin status" do
put api("/users/#{admin_user.id}", admin), params: { can_create_group: false }
diff --git a/spec/serializers/container_repositories_serializer_spec.rb b/spec/serializers/container_repositories_serializer_spec.rb
new file mode 100644
index 00000000000..382778389b3
--- /dev/null
+++ b/spec/serializers/container_repositories_serializer_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ContainerRepositoriesSerializer do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:resource) { create(:container_repository, name: 'image', project: project) }
+ let(:params) { { current_user: user, project: project } }
+
+ before do
+ project.add_developer(user)
+
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags(repository: /image/, tags: %w(rootA latest))
+ end
+
+ describe '#represent' do
+ subject do
+ described_class.new(params).represent(resource)
+ end
+
+ it 'has basic attributes' do
+ expect(subject).to include(:id, :name, :path, :location, :created_at, :tags_path, :destroy_path)
+ end
+ end
+
+ describe '#represent_read_only' do
+ subject do
+ described_class.new(current_user: user, project: project).represent_read_only(resource)
+ end
+
+ it 'does not include destroy_path' do
+ expect(subject).to include(:id, :name, :path, :location, :created_at, :tags_path)
+ expect(subject).not_to include(:destroy_path)
+ end
+ end
+
+ describe '#with_pagination' do
+ let(:request) do
+ double(
+ url: "#{Gitlab.config.gitlab.url}:8080/#{project.namespace_id}/#{project.id}/container_registry?#{query.to_query}",
+ query_parameters: query
+ )
+ end
+
+ let(:response) { spy('response') }
+ let(:resource) { ContainerRepository.all }
+ let(:query) { { page: 1, per_page: 2 } }
+
+ let(:serializer) do
+ described_class
+ .new(current_user: user, project: project)
+ .with_pagination(request, response)
+ end
+
+ subject do
+ serializer.represent(resource)
+ end
+
+ it 'creates a paginated serializer' do
+ expect(serializer).to be_paginated
+ end
+
+ context 'when multiple ContainerRepository objects are serialized' do
+ before do
+ create_list(:container_repository, 5, project: project)
+ end
+
+ it 'serializes appropriate number of objects' do
+ expect(subject.count).to be 2
+ end
+
+ it 'appends relevant headers' do
+ expect(response).to include_pagination_headers
+ expect(response).to receive(:[]=).with('X-Total', '5')
+ expect(response).to receive(:[]=).with('X-Total-Pages', '3')
+ expect(response).to receive(:[]=).with('X-Per-Page', '2')
+
+ subject
+ end
+ end
+ end
+end
diff --git a/spec/serializers/diff_file_entity_spec.rb b/spec/serializers/diff_file_entity_spec.rb
index 65b62f8aa16..3e341a58a15 100644
--- a/spec/serializers/diff_file_entity_spec.rb
+++ b/spec/serializers/diff_file_entity_spec.rb
@@ -49,7 +49,7 @@ describe DiffFileEntity do
end
end
- context '#parallel_diff_lines' do
+ describe '#parallel_diff_lines' do
let(:options) { { diff_view: :parallel } }
it 'exposes parallel diff lines correctly' do
diff --git a/spec/services/branches/delete_merged_service_spec.rb b/spec/services/branches/delete_merged_service_spec.rb
index 962af8110f7..5c87f156ec7 100644
--- a/spec/services/branches/delete_merged_service_spec.rb
+++ b/spec/services/branches/delete_merged_service_spec.rb
@@ -9,7 +9,7 @@ describe Branches::DeleteMergedService do
let(:project) { create(:project, :repository) }
- context '#execute' do
+ describe '#execute' do
it 'deletes a branch that was merged' do
service.execute
@@ -74,7 +74,7 @@ describe Branches::DeleteMergedService do
end
end
- context '#async_execute' do
+ describe '#async_execute' do
it 'calls DeleteMergedBranchesWorker async' do
expect(DeleteMergedBranchesWorker).to receive(:perform_async)
diff --git a/spec/services/ci/ensure_stage_service_spec.rb b/spec/services/ci/ensure_stage_service_spec.rb
index de07a1ae238..8a270d77bae 100644
--- a/spec/services/ci/ensure_stage_service_spec.rb
+++ b/spec/services/ci/ensure_stage_service_spec.rb
@@ -44,7 +44,7 @@ describe Ci::EnsureStageService, '#execute' do
it 'retries up to two times' do
job.assign_attributes(stage_id: nil)
- expect(service).to receive(:find_stage).exactly(2).times
+ expect(service).to receive(:find_stage).twice
expect { service.execute(job) }
.to raise_error(Ci::EnsureStageService::EnsureStageError)
diff --git a/spec/services/clusters/cleanup/app_service_spec.rb b/spec/services/clusters/cleanup/app_service_spec.rb
index cc27f409086..14bfca02fee 100644
--- a/spec/services/clusters/cleanup/app_service_spec.rb
+++ b/spec/services/clusters/cleanup/app_service_spec.rb
@@ -85,7 +85,7 @@ describe Clusters::Cleanup::AppService do
it 'logs application uninstalls and next execution' do
expect(logger).to receive(:info)
- .with(log_meta.merge(event: :uninstalling_app, application: kind_of(String))).exactly(2).times
+ .with(log_meta.merge(event: :uninstalling_app, application: kind_of(String))).twice
expect(logger).to receive(:info)
.with(log_meta.merge(event: :scheduling_execution, next_execution: 1))
diff --git a/spec/services/git/branch_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb
index c64b93a2532..8b4f45010ed 100644
--- a/spec/services/git/branch_push_service_spec.rb
+++ b/spec/services/git/branch_push_service_spec.rb
@@ -12,6 +12,7 @@ describe Git::BranchPushService, services: true do
let(:newrev) { sample_commit.id }
let(:branch) { 'master' }
let(:ref) { "refs/heads/#{branch}" }
+ let(:push_options) { nil }
before do
project.add_maintainer(user)
@@ -19,7 +20,7 @@ describe Git::BranchPushService, services: true do
describe 'Push branches' do
subject do
- execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
+ execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref, push_options: push_options)
end
context 'new branch' do
@@ -113,6 +114,20 @@ describe Git::BranchPushService, services: true do
expect { subject }.not_to change { Ci::Pipeline.count }
end
+
+ context 'with push options' do
+ let(:push_options) { ['mr.create'] }
+
+ it 'sanitizes push options' do
+ allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
+ expect(Sidekiq.logger).to receive(:warn) do |args|
+ pipeline_params = args[:pipeline_params]
+ expect(pipeline_params.keys).to match_array(%i(before after ref variables_attributes checkout_sha))
+ end
+
+ expect { subject }.not_to change { Ci::Pipeline.count }
+ end
+ end
end
end
@@ -637,8 +652,8 @@ describe Git::BranchPushService, services: true do
end
end
- def execute_service(project, user, change)
- service = described_class.new(project, user, change: change)
+ def execute_service(project, user, change, push_options = {})
+ service = described_class.new(project, user, change: change, push_options: push_options)
service.execute
service
end
diff --git a/spec/services/labels/available_labels_service_spec.rb b/spec/services/labels/available_labels_service_spec.rb
index 4d5c87ecc53..ce120344f16 100644
--- a/spec/services/labels/available_labels_service_spec.rb
+++ b/spec/services/labels/available_labels_service_spec.rb
@@ -12,7 +12,7 @@ describe Labels::AvailableLabelsService do
let(:other_group_label) { create(:group_label) }
let(:labels) { [project_label, other_project_label, group_label, other_group_label] }
- context '#find_or_create_by_titles' do
+ describe '#find_or_create_by_titles' do
let(:label_titles) { labels.map(&:title).push('non existing title') }
context 'when parent is a project' do
@@ -64,7 +64,7 @@ describe Labels::AvailableLabelsService do
end
end
- context '#filter_labels_ids_in_param' do
+ describe '#filter_labels_ids_in_param' do
let(:label_ids) { labels.map(&:id).push(99999) }
context 'when parent is a project' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 1f1ccff2ba8..e7d0e91bced 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -2264,7 +2264,7 @@ describe NotificationService, :mailer do
end
it 'filters out guests when new note is created' do
- expect(SentNotification).to receive(:record).with(merge_request, any_args).exactly(1).times
+ expect(SentNotification).to receive(:record).with(merge_request, any_args).once
notification.new_note(note)
diff --git a/spec/services/projects/batch_open_issues_count_service_spec.rb b/spec/services/projects/batch_open_issues_count_service_spec.rb
index e978334d68b..8cb0ce03fba 100644
--- a/spec/services/projects/batch_open_issues_count_service_spec.rb
+++ b/spec/services/projects/batch_open_issues_count_service_spec.rb
@@ -8,7 +8,7 @@ describe Projects::BatchOpenIssuesCountService do
let(:subject) { described_class.new([project_1, project_2]) }
- context '#refresh_cache', :use_clean_rails_memory_store_caching do
+ describe '#refresh_cache', :use_clean_rails_memory_store_caching do
before do
create(:issue, project: project_1)
create(:issue, project: project_1, confidential: true)
diff --git a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
index b0827f6a2ee..7c7e188a12d 100644
--- a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
@@ -14,7 +14,7 @@ describe Projects::HashedStorage::MigrateAttachmentsService do
let(:old_disk_path) { File.join(base_path(legacy_storage), upload.path) }
let(:new_disk_path) { File.join(base_path(hashed_storage), upload.path) }
- context '#execute' do
+ describe '#execute' do
context 'when succeeds' do
it 'moves attachments to hashed storage layout' do
expect(File.file?(old_disk_path)).to be_truthy
@@ -102,13 +102,13 @@ describe Projects::HashedStorage::MigrateAttachmentsService do
end
end
- context '#old_disk_path' do
+ describe '#old_disk_path' do
it 'returns old disk_path for project' do
expect(service.old_disk_path).to eq(project.full_path)
end
end
- context '#new_disk_path' do
+ describe '#new_disk_path' do
it 'returns new disk_path for project' do
service.execute
@@ -116,7 +116,7 @@ describe Projects::HashedStorage::MigrateAttachmentsService do
end
end
- context '#target_path_discardable?' do
+ describe '#target_path_discardable?' do
it 'returns true when it include only items on the discardable list' do
hashed_attachments_path = File.join(base_path(hashed_storage))
Projects::HashedStorage::MigrateAttachmentsService::DISCARDABLE_PATHS.each do |path_fragment|
diff --git a/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb b/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb
index 98b343371df..54695e6e48f 100644
--- a/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb
+++ b/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb
@@ -14,7 +14,7 @@ describe Projects::HashedStorage::RollbackAttachmentsService do
let(:old_disk_path) { File.join(base_path(hashed_storage), upload.path) }
let(:new_disk_path) { File.join(base_path(legacy_storage), upload.path) }
- context '#execute' do
+ describe '#execute' do
context 'when succeeds' do
it 'moves attachments to legacy storage layout' do
expect(File.file?(old_disk_path)).to be_truthy
@@ -86,13 +86,13 @@ describe Projects::HashedStorage::RollbackAttachmentsService do
end
end
- context '#old_disk_path' do
+ describe '#old_disk_path' do
it 'returns old disk_path for project' do
expect(service.old_disk_path).to eq(project.disk_path)
end
end
- context '#new_disk_path' do
+ describe '#new_disk_path' do
it 'returns new disk_path for project' do
service.execute
diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb
index 60804a8dba6..98a27a71c26 100644
--- a/spec/services/projects/housekeeping_service_spec.rb
+++ b/spec/services/projects/housekeeping_service_spec.rb
@@ -75,7 +75,7 @@ describe Projects::HousekeepingService do
# At push 200
expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :gc, :the_lease_key, :the_uuid)
- .exactly(1).times
+ .once
# At push 50, 100, 150
expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :full_repack, :the_lease_key, :the_uuid)
.exactly(3).times
diff --git a/spec/services/projects/open_issues_count_service_spec.rb b/spec/services/projects/open_issues_count_service_spec.rb
index 04f1353c499..c1d49befeb9 100644
--- a/spec/services/projects/open_issues_count_service_spec.rb
+++ b/spec/services/projects/open_issues_count_service_spec.rb
@@ -57,7 +57,7 @@ describe Projects::OpenIssuesCountService, :use_clean_rails_memory_store_caching
end
end
- context '#refresh_cache' do
+ describe '#refresh_cache' do
before do
create(:issue, :opened, project: project)
create(:issue, :opened, project: project)
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 81012eba06d..7db94d4a4ac 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1884,7 +1884,7 @@ describe QuickActions::InterpretService do
end
end
- context "#commands_executed_count" do
+ describe "#commands_executed_count" do
it 'counts commands executed' do
content = "/close and \n/assign me and \n/title new title"
diff --git a/spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb b/spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb
index 56f9e811799..ec1c58e5b67 100644
--- a/spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb
@@ -9,7 +9,7 @@ RSpec.shared_examples 'issues list service' do
described_class.new(parent, user, params).execute
end
- context '#metadata' do
+ describe '#metadata' do
it 'returns issues count for list' do
params = { board_id: board.id, id: list1.id }
diff --git a/spec/tasks/gitlab/cleanup_rake_spec.rb b/spec/tasks/gitlab/cleanup_rake_spec.rb
index 3c3e5eea838..92ccc195a9a 100644
--- a/spec/tasks/gitlab/cleanup_rake_spec.rb
+++ b/spec/tasks/gitlab/cleanup_rake_spec.rb
@@ -16,10 +16,10 @@ describe 'gitlab:cleanup rake tasks' do
let!(:logger) { double(:logger) }
before do
- expect(main_object).to receive(:logger).and_return(logger).at_least(1).times
+ expect(main_object).to receive(:logger).and_return(logger).at_least(:once)
- allow(logger).to receive(:info).at_least(1).times
- allow(logger).to receive(:debug).at_least(1).times
+ allow(logger).to receive(:info).at_least(:once)
+ allow(logger).to receive(:debug).at_least(:once)
end
context 'with a fixable orphaned project upload file' do
diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb
index 4329171f0be..80efdb88585 100644
--- a/spec/uploaders/gitlab_uploader_spec.rb
+++ b/spec/uploaders/gitlab_uploader_spec.rb
@@ -59,7 +59,7 @@ describe GitlabUploader do
describe '#cache!' do
it 'moves the file from the working directory to the cache directory' do
# One to get the work dir, the other to remove it
- expect(subject).to receive(:workfile_path).exactly(2).times.and_call_original
+ expect(subject).to receive(:workfile_path).twice.and_call_original
# Test https://github.com/carrierwavesubject/carrierwave/blob/v1.0.0/lib/carrierwave/sanitized_file.rb#L200
expect(FileUtils).to receive(:mv).with(anything, /^#{subject.work_dir}/).and_call_original
expect(FileUtils).to receive(:mv).with(/^#{subject.work_dir}/, /#{subject.cache_dir}/).and_call_original
diff --git a/spec/uploaders/namespace_file_uploader_spec.rb b/spec/uploaders/namespace_file_uploader_spec.rb
index aa98b3e2828..bc8d6a33e85 100644
--- a/spec/uploaders/namespace_file_uploader_spec.rb
+++ b/spec/uploaders/namespace_file_uploader_spec.rb
@@ -37,7 +37,7 @@ describe NamespaceFileUploader do
end
end
- context '.base_dir' do
+ describe '.base_dir' do
it 'returns local storage base_dir without store param' do
expect(described_class.base_dir(group)).to eq("uploads/-/system/namespace/#{group.id}")
end
diff --git a/spec/workers/create_gpg_signature_worker_spec.rb b/spec/workers/create_gpg_signature_worker_spec.rb
index ae09b4b77f1..2504a6474db 100644
--- a/spec/workers/create_gpg_signature_worker_spec.rb
+++ b/spec/workers/create_gpg_signature_worker_spec.rb
@@ -31,7 +31,7 @@ describe CreateGpgSignatureWorker do
allow(Gitlab::Gpg::Commit).to receive(:new).and_return(gpg_commit)
allow(Gitlab::Gpg::Commit).to receive(:new).with(commits.first).and_raise(StandardError)
- expect(gpg_commit).to receive(:signature).exactly(2).times
+ expect(gpg_commit).to receive(:signature).twice
subject
end