summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml19
-rw-r--r--.gitlab/ci/pages.gitlab-ci.yml3
-rw-r--r--.gitlab/ci/qa.gitlab-ci.yml38
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml21
-rw-r--r--.gitlab/ci/yaml.gitlab-ci.yml1
-rw-r--r--.rubocop.yml2
-rw-r--r--.rubocop_todo.yml7
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile7
-rw-r--r--Gemfile.lock13
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue2
-rw-r--r--app/assets/javascripts/boards/components/project_select.vue12
-rw-r--r--app/assets/javascripts/boards/models/issue.js4
-rw-r--r--app/assets/javascripts/branches/divergence_graph.js5
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js49
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js29
-rw-r--r--app/assets/javascripts/flash.js21
-rw-r--r--app/assets/javascripts/groups/components/app.vue7
-rw-r--r--app/assets/javascripts/groups/service/groups_service.js21
-rw-r--r--app/assets/javascripts/jobs/components/job_app.vue6
-rw-r--r--app/assets/javascripts/jobs/components/log/line.vue28
-rw-r--r--app/assets/javascripts/jobs/components/log/line_header.vue45
-rw-r--r--app/assets/javascripts/jobs/components/log/line_number.vue52
-rw-r--r--app/assets/javascripts/jobs/index.js2
-rw-r--r--app/assets/javascripts/jobs/store/utils.js40
-rw-r--r--app/assets/javascripts/monitoring/components/charts/area.vue304
-rw-r--r--app/assets/javascripts/pages/profiles/two_factor_auths/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/project.js7
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/constants.js2
-rw-r--r--app/assets/stylesheets/framework/flash.scss47
-rw-r--r--app/assets/stylesheets/framework/layout.scss9
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/pages/clusters.scss9
-rw-r--r--app/controllers/admin/groups_controller.rb6
-rw-r--r--app/finders/issuable_finder.rb6
-rw-r--r--app/finders/todos_finder.rb2
-rw-r--r--app/graphql/mutations/notes/create/base.rb4
-rw-r--r--app/graphql/resolvers/full_path_resolver.rb2
-rw-r--r--app/graphql/resolvers/issues_resolver.rb4
-rw-r--r--app/graphql/resolvers/merge_requests_resolver.rb6
-rw-r--r--app/graphql/resolvers/namespace_projects_resolver.rb4
-rw-r--r--app/helpers/boards_helper.rb2
-rw-r--r--app/helpers/jobs_helper.rb19
-rw-r--r--app/mailers/emails/notes.rb25
-rw-r--r--app/models/board.rb1
-rw-r--r--app/models/ci/pipeline.rb31
-rw-r--r--app/models/concerns/issuable.rb4
-rw-r--r--app/models/concerns/routable.rb16
-rw-r--r--app/models/event.rb1
-rw-r--r--app/models/member.rb2
-rw-r--r--app/models/merge_request.rb4
-rw-r--r--app/models/merge_request_diff.rb6
-rw-r--r--app/models/milestone.rb9
-rw-r--r--app/models/milestone_release.rb17
-rw-r--r--app/models/note.rb1
-rw-r--r--app/models/release.rb7
-rw-r--r--app/models/repository.rb4
-rw-r--r--app/models/service.rb8
-rw-r--r--app/models/todo.rb1
-rw-r--r--app/policies/board_policy.rb18
-rw-r--r--app/policies/concerns/find_group_projects.rb13
-rw-r--r--app/policies/group_policy.rb4
-rw-r--r--app/presenters/ci/build_runner_presenter.rb4
-rw-r--r--app/presenters/ci/pipeline_presenter.rb12
-rw-r--r--app/presenters/clusterable_presenter.rb5
-rw-r--r--app/serializers/entity_date_helper.rb12
-rw-r--r--app/serializers/pipeline_entity.rb16
-rw-r--r--app/services/audit_event_service.rb8
-rw-r--r--app/services/auth/container_registry_authentication_service.rb12
-rw-r--r--app/services/auto_merge_service.rb2
-rw-r--r--app/services/clusters/applications/check_installation_progress_service.rb4
-rw-r--r--app/services/clusters/applications/check_uninstall_progress_service.rb6
-rw-r--r--app/services/event_create_service.rb13
-rw-r--r--app/services/issuable_base_service.rb1
-rw-r--r--app/services/merge_requests/rebase_service.rb2
-rw-r--r--app/services/milestones/find_or_create_service.rb34
-rw-r--r--app/services/milestones/transfer_service.rb84
-rw-r--r--app/services/notification_service.rb2
-rw-r--r--app/services/projects/destroy_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_download_link_list_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_list_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_object_download_list_service.rb4
-rw-r--r--app/services/projects/open_issues_count_service.rb4
-rw-r--r--app/services/projects/transfer_service.rb3
-rw-r--r--app/services/projects/update_pages_service.rb4
-rw-r--r--app/services/releases/concerns.rb21
-rw-r--r--app/services/releases/create_service.rb4
-rw-r--r--app/services/releases/update_service.rb3
-rw-r--r--app/services/submit_usage_ping_service.rb2
-rw-r--r--app/services/system_hooks_service.rb2
-rw-r--r--app/services/wikis/create_attachment_service.rb2
-rw-r--r--app/uploaders/object_storage.rb2
-rw-r--r--app/validators/addressable_url_validator.rb8
-rw-r--r--app/views/admin/background_jobs/show.html.haml12
-rw-r--r--app/views/admin/dashboard/index.html.haml316
-rw-r--r--app/views/admin/groups/index.html.haml32
-rw-r--r--app/views/admin/health_check/show.html.haml74
-rw-r--r--app/views/admin/jobs/index.html.haml31
-rw-r--r--app/views/admin/logs/show.html.haml46
-rw-r--r--app/views/admin/projects/index.html.haml73
-rw-r--r--app/views/admin/requests_profiles/index.html.haml42
-rw-r--r--app/views/admin/runners/index.html.haml244
-rw-r--r--app/views/admin/system_info/show.html.haml68
-rw-r--r--app/views/admin/users/index.html.haml140
-rw-r--r--app/views/clusters/clusters/_configure.html.haml26
-rw-r--r--app/views/clusters/clusters/show.html.haml35
-rw-r--r--app/views/clusters/clusters/user/_form.html.haml1
-rw-r--r--app/views/clusters/platforms/kubernetes/_form.html.haml2
-rw-r--r--app/views/dashboard/activity.html.haml11
-rw-r--r--app/views/dashboard/projects/index.html.haml16
-rw-r--r--app/views/dashboard/projects/starred.html.haml14
-rw-r--r--app/views/groups/labels/index.html.haml34
-rw-r--r--app/views/groups/milestones/new.html.haml10
-rw-r--r--app/views/groups/show.html.haml3
-rw-r--r--app/views/instance_statistics/cohorts/index.html.haml26
-rw-r--r--app/views/instance_statistics/conversational_development_index/index.html.haml1
-rw-r--r--app/views/layouts/_flash.html.haml10
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/projects/activity.html.haml6
-rw-r--r--app/views/projects/blame/show.html.haml78
-rw-r--r--app/views/projects/blob/edit.html.haml50
-rw-r--r--app/views/projects/blob/show.html.haml19
-rw-r--r--app/views/projects/branches/index.html.haml108
-rw-r--r--app/views/projects/commit/show.html.haml1
-rw-r--r--app/views/projects/commits/show.html.haml50
-rw-r--r--app/views/projects/compare/index.html.haml26
-rw-r--r--app/views/projects/compare/show.html.haml40
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml3
-rw-r--r--app/views/projects/empty.html.haml3
-rw-r--r--app/views/projects/environments/edit.html.haml10
-rw-r--r--app/views/projects/environments/folder.html.haml4
-rw-r--r--app/views/projects/environments/index.html.haml4
-rw-r--r--app/views/projects/environments/metrics.html.haml3
-rw-r--r--app/views/projects/environments/new.html.haml10
-rw-r--r--app/views/projects/environments/show.html.haml120
-rw-r--r--app/views/projects/environments/terminal.html.haml26
-rw-r--r--app/views/projects/graphs/charts.html.haml5
-rw-r--r--app/views/projects/graphs/show.html.haml3
-rw-r--r--app/views/projects/imports/show.html.haml1
-rw-r--r--app/views/projects/issues/index.html.haml22
-rw-r--r--app/views/projects/jobs/index.html.haml24
-rw-r--r--app/views/projects/jobs/show.html.haml10
-rw-r--r--app/views/projects/jobs/terminal.html.haml3
-rw-r--r--app/views/projects/labels/edit.html.haml10
-rw-r--r--app/views/projects/labels/index.html.haml78
-rw-r--r--app/views/projects/labels/new.html.haml10
-rw-r--r--app/views/projects/merge_requests/index.html.haml27
-rw-r--r--app/views/projects/milestones/_deprecation_message.html.haml7
-rw-r--r--app/views/projects/milestones/edit.html.haml12
-rw-r--r--app/views/projects/milestones/index.html.haml36
-rw-r--r--app/views/projects/milestones/new.html.haml10
-rw-r--r--app/views/projects/milestones/show.html.haml111
-rw-r--r--app/views/projects/network/_head.html.haml13
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml30
-rw-r--r--app/views/projects/pipelines/charts.html.haml12
-rw-r--r--app/views/projects/pipelines/index.html.haml24
-rw-r--r--app/views/projects/pipelines/show.html.haml3
-rw-r--r--app/views/projects/project_templates/_built_in_templates.html.haml4
-rw-r--r--app/views/projects/releases/index.html.haml4
-rw-r--r--app/views/projects/serverless/functions/index.html.haml3
-rw-r--r--app/views/projects/serverless/functions/show.html.haml3
-rw-r--r--app/views/projects/settings/ci_cd/_autodevops_form.html.haml18
-rw-r--r--app/views/projects/show.html.haml3
-rw-r--r--app/views/projects/tags/index.html.haml3
-rw-r--r--app/views/projects/tags/releases/edit.html.haml31
-rw-r--r--app/views/projects/tags/show.html.haml74
-rw-r--r--app/views/projects/tree/show.html.haml6
-rw-r--r--app/views/projects/wikis/pages.html.haml44
-rw-r--r--app/views/shared/empty_states/_priority_labels.html.haml4
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--app/workers/hashed_storage/base_worker.rb2
-rw-r--r--app/workers/stuck_ci_jobs_worker.rb2
-rwxr-xr-xbin/rspec-stackprof2
-rw-r--r--changelogs/unreleased/36765-flash-notification.yml5
-rw-r--r--changelogs/unreleased/40096-allow-ci-token-to-delete-from-registry.yml5
-rw-r--r--changelogs/unreleased/51372-remove-milestone-tabs-deprecation-message.yml5
-rw-r--r--changelogs/unreleased/60372-milestone-link-prevent-delete-issue-after-move-it-to-another-projec.yml5
-rw-r--r--changelogs/unreleased/62402-milestone-release-be.yml5
-rw-r--r--changelogs/unreleased/62591-fix-milestone-due-date-today-wording.yml5
-rw-r--r--changelogs/unreleased/64009-show-a-meaningful-error-message-when-due-quick_actions-command-fail.yml5
-rw-r--r--changelogs/unreleased/66454-base-components.yml5
-rw-r--r--changelogs/unreleased/66454-utils-parser.yml5
-rw-r--r--changelogs/unreleased/ab-add-index-for-ci-builds-metrics.yml5
-rw-r--r--changelogs/unreleased/ab-remove-support-bot-column.yml5
-rw-r--r--changelogs/unreleased/ab-routable-nplus1.yml5
-rw-r--r--changelogs/unreleased/ab-unconfirmed-email-index.yml5
-rw-r--r--changelogs/unreleased/add-notification-reason-to-note-emails.yml5
-rw-r--r--changelogs/unreleased/change-prioritized-labels-empty-state-message.yml5
-rw-r--r--changelogs/unreleased/change-role-system-hook.yml5
-rw-r--r--changelogs/unreleased/cluster-form-ca-cert-larger.yml5
-rw-r--r--changelogs/unreleased/fix-regression-remove-installation-pod.yml5
-rw-r--r--changelogs/unreleased/fj-66723-add-dns-rebinding-protection-check.yml5
-rw-r--r--changelogs/unreleased/fj-remove-dns-protection-when-validating.yml5
-rw-r--r--changelogs/unreleased/issue_54042.yml5
-rw-r--r--changelogs/unreleased/je-add-cluster-domain-warning.yml5
-rw-r--r--changelogs/unreleased/je-add-group-deployments-page-fe.yml5
-rw-r--r--changelogs/unreleased/persist-needs-error.yml5
-rw-r--r--changelogs/unreleased/remove-vue-resource-from-group-service.yml5
-rw-r--r--changelogs/unreleased/remove-vue-resource-from-issue.yml5
-rw-r--r--changelogs/unreleased/sh-suppress-diverging-count-commits-request.yml5
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/routes.rb2
-rw-r--r--config/sidekiq_queues.yml1
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb6
-rw-r--r--db/migrate/20190722144316_create_milestone_releases_table.rb20
-rw-r--r--db/migrate/20190826100605_add_group_column_to_events.rb9
-rw-r--r--db/migrate/20190828110802_add_not_null_constraints_to_prometheus_metrics_y_label_and_unit.rb8
-rw-r--r--db/migrate/20190902152329_add_index_for_ci_builds_metrics.rb19
-rw-r--r--db/migrate/20190904173203_add_index_on_users_unconfirmed_email.rb17
-rw-r--r--db/post_migrate/20190902160015_remove_support_bot_column_from_users.rb19
-rw-r--r--db/schema.rb20
-rw-r--r--doc/README.md5
-rw-r--r--doc/administration/geo/disaster_recovery/index.md2
-rw-r--r--doc/administration/geo/replication/updating_the_geo_nodes.md447
-rw-r--r--doc/administration/geo/replication/version_specific_updates.md426
-rw-r--r--doc/administration/gitaly/index.md2
-rw-r--r--doc/administration/index.md37
-rw-r--r--doc/administration/logs.md13
-rw-r--r--doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md1040
-rw-r--r--doc/administration/troubleshooting/kubernetes_cheat_sheet.md10
-rw-r--r--doc/administration/troubleshooting/linux_cheat_sheet.md339
-rw-r--r--doc/administration/troubleshooting/test_environments.md126
-rw-r--r--doc/api/groups.md3
-rw-r--r--doc/api/issues.md12
-rw-r--r--doc/api/releases/index.md94
-rw-r--r--doc/api/templates/dockerfiles.md20
-rw-r--r--doc/api/templates/gitignores.md22
-rw-r--r--doc/api/templates/gitlab_ci_ymls.md20
-rw-r--r--doc/api/templates/licenses.md21
-rw-r--r--doc/ci/docker/using_docker_build.md7
-rw-r--r--doc/ci/environments.md5
-rw-r--r--doc/ci/large_repositories/index.md2
-rw-r--r--doc/ci/multi_project_pipelines.md12
-rw-r--r--doc/ci/variables/README.md2
-rw-r--r--doc/ci/yaml/README.md137
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/architecture.md10
-rw-r--r--doc/development/background_migrations.md15
-rw-r--r--doc/development/code_review.md11
-rw-r--r--doc/development/dangerbot.md116
-rw-r--r--doc/development/database_review.md3
-rw-r--r--doc/development/documentation/site_architecture/global_nav.md87
-rw-r--r--doc/development/documentation/site_architecture/index.md8
-rw-r--r--doc/development/gotchas.md4
-rw-r--r--doc/development/integrations/jira_connect.md6
-rw-r--r--doc/development/prometheus_metrics.md23
-rw-r--r--doc/development/testing_guide/end_to_end/best_practices.md17
-rw-r--r--doc/development/testing_guide/end_to_end/index.md2
-rw-r--r--doc/development/testing_guide/review_apps.md4
-rw-r--r--doc/raketasks/backup_restore.md6
-rw-r--r--doc/system_hooks/system_hooks.md40
-rw-r--r--doc/user/application_security/container_scanning/index.md2
-rw-r--r--doc/user/application_security/dast/index.md6
-rw-r--r--doc/user/application_security/dependency_scanning/index.md6
-rw-r--r--doc/user/application_security/sast/img/security_report.pngbin38475 -> 0 bytes
-rw-r--r--doc/user/application_security/sast/index.md12
-rwxr-xr-x[-rw-r--r--]doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.pngbin60530 -> 61667 bytes
-rwxr-xr-xdoc/user/application_security/security_dashboard/img/pipeline_security_dashboard_v12_3.pngbin0 -> 52247 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard.pngbin73425 -> 0 bytes
-rwxr-xr-xdoc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.pngbin0 -> 48767 bytes
-rw-r--r--doc/user/application_security/security_dashboard/index.md24
-rw-r--r--doc/user/group/index.md6
-rw-r--r--doc/user/instance/clusters/index.md2
-rw-r--r--doc/user/permissions.md4
-rw-r--r--doc/user/project/import/gemnasium.md2
-rw-r--r--doc/user/project/import/img/gemnasium/report.pngbin144883 -> 0 bytes
-rw-r--r--doc/user/project/operations/feature_flags.md10
-rw-r--r--doc/user/project/quick_actions.md7
-rw-r--r--lib/api/api.rb2
-rw-r--r--lib/api/entities.rb6
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/internal.rb294
-rw-r--r--lib/api/internal/base.rb296
-rw-r--r--lib/api/release/links.rb4
-rw-r--r--lib/api/releases.rb10
-rw-r--r--lib/gitlab/auth.rb3
-rw-r--r--lib/gitlab/auth/unique_ips_limiter.rb2
-rw-r--r--lib/gitlab/auth/user_auth_finders.rb2
-rw-r--r--lib/gitlab/background_migration/merge_request_assignees_migration_progress_check.rb2
-rw-r--r--lib/gitlab/background_migration/prepare_untracked_uploads.rb8
-rw-r--r--lib/gitlab/bitbucket_server_import/importer.rb2
-rw-r--r--lib/gitlab/checks/lfs_check.rb4
-rw-r--r--lib/gitlab/checks/project_created.rb2
-rw-r--r--lib/gitlab/checks/project_moved.rb2
-rw-r--r--lib/gitlab/ci/build/port.rb4
-rw-r--r--lib/gitlab/ci/build/step.rb6
-rw-r--r--lib/gitlab/ci/config/entry/cache.rb2
-rw-r--r--lib/gitlab/ci/config/external/file/template.rb2
-rw-r--r--lib/gitlab/ci/cron_parser.rb4
-rw-r--r--lib/gitlab/ci/pipeline/chain/helpers.rb7
-rw-r--r--lib/gitlab/ci/pipeline/chain/populate.rb2
-rw-r--r--lib/gitlab/ci/reports/test_case.rb8
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml22
-rw-r--r--lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml5
-rw-r--r--lib/gitlab/cleanup/project_upload_file_finder.rb6
-rw-r--r--lib/gitlab/correlation_id.rb40
-rw-r--r--lib/gitlab/danger/helper.rb3
-rw-r--r--lib/gitlab/database/sha_attribute.rb2
-rw-r--r--lib/gitlab/downtime_check/message.rb4
-rw-r--r--lib/gitlab/ee_compat_check.rb5
-rw-r--r--lib/gitlab/etag_caching/store.rb2
-rw-r--r--lib/gitlab/git.rb6
-rw-r--r--lib/gitlab/git/diff_collection.rb6
-rw-r--r--lib/gitlab/git/lfs_pointer_file.rb4
-rw-r--r--lib/gitlab/git/repository.rb4
-rw-r--r--lib/gitlab/git/util.rb2
-rw-r--r--lib/gitlab/github_import/issuable_finder.rb2
-rw-r--r--lib/gitlab/github_import/label_finder.rb2
-rw-r--r--lib/gitlab/github_import/milestone_finder.rb2
-rw-r--r--lib/gitlab/github_import/page_counter.rb2
-rw-r--r--lib/gitlab/github_import/parallel_scheduling.rb2
-rw-r--r--lib/gitlab/github_import/user_finder.rb6
-rw-r--r--lib/gitlab/graphql/authorize/authorize_field_service.rb12
-rw-r--r--lib/gitlab/graphql/authorize/authorize_resource.rb10
-rw-r--r--lib/gitlab/graphql/loaders/batch_lfs_oid_loader.rb2
-rw-r--r--lib/gitlab/graphql/loaders/batch_model_loader.rb2
-rw-r--r--lib/gitlab/graphql/loaders/batch_project_statistics_loader.rb2
-rw-r--r--lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader.rb2
-rw-r--r--lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb2
-rw-r--r--lib/gitlab/graphql/representation/submodule_tree_entry.rb2
-rw-r--r--lib/gitlab/graphql/representation/tree_entry.rb2
-rw-r--r--lib/gitlab/health_checks/gitaly_check.rb2
-rw-r--r--lib/gitlab/import_export.rb2
-rw-r--r--lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb2
-rw-r--r--lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb6
-rw-r--r--lib/gitlab/incoming_email.rb6
-rw-r--r--lib/gitlab/job_waiter.rb2
-rw-r--r--lib/gitlab/jwt_authenticatable.rb42
-rw-r--r--lib/gitlab/kubernetes/helm.rb12
-rw-r--r--lib/gitlab/kubernetes/pod.rb10
-rw-r--r--lib/gitlab/logger.rb2
-rw-r--r--lib/gitlab/metrics/samplers/ruby_sampler.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/action_view.rb2
-rw-r--r--lib/gitlab/metrics/transaction.rb2
-rw-r--r--lib/gitlab/metrics/web_transaction.rb4
-rw-r--r--lib/gitlab/middleware/multipart.rb2
-rw-r--r--lib/gitlab/middleware/read_only/controller.rb4
-rw-r--r--lib/gitlab/optimistic_locking.rb3
-rw-r--r--lib/gitlab/path_regex.rb6
-rw-r--r--lib/gitlab/performance_bar.rb2
-rw-r--r--lib/gitlab/polling_interval.rb2
-rw-r--r--lib/gitlab/private_commit_email.rb2
-rw-r--r--lib/gitlab/profiler.rb2
-rw-r--r--lib/gitlab/prometheus/additional_metrics_parser.rb2
-rw-r--r--lib/gitlab/query_limiting/middleware.rb4
-rw-r--r--lib/gitlab/quick_actions/issuable_actions.rb5
-rw-r--r--lib/gitlab/quick_actions/issue_actions.rb6
-rw-r--r--lib/gitlab/redis/cache.rb6
-rw-r--r--lib/gitlab/redis/queues.rb8
-rw-r--r--lib/gitlab/redis/shared_state.rb12
-rw-r--r--lib/gitlab/redis/wrapper.rb4
-rw-r--r--lib/gitlab/request_profiler.rb2
-rw-r--r--lib/gitlab/shard_health_cache.rb2
-rw-r--r--lib/gitlab/sidekiq_monitor.rb2
-rw-r--r--lib/gitlab/sidekiq_status.rb2
-rw-r--r--lib/gitlab/tracing.rb2
-rw-r--r--lib/gitlab/url_blocker.rb8
-rw-r--r--lib/gitlab/url_helpers.rb2
-rw-r--r--lib/gitlab/workhorse.rb40
-rw-r--r--lib/peek/views/active_record.rb8
-rw-r--r--lib/peek/views/gitaly.rb10
-rw-r--r--lib/system_check/incoming_email/foreman_configured_check.rb25
-rw-r--r--lib/system_check/incoming_email_check.rb2
-rw-r--r--locale/gitlab.pot32
-rw-r--r--package.json6
-rwxr-xr-xscripts/frontend/check_dependencies.sh11
-rwxr-xr-xscripts/review_apps/review-apps.sh7
-rw-r--r--spec/config/smime_signature_settings_spec.rb2
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb2
-rw-r--r--spec/controllers/sent_notifications_controller_spec.rb2
-rw-r--r--spec/factories/milestone_releases.rb14
-rw-r--r--spec/features/admin/admin_disables_git_access_protocol_spec.rb2
-rw-r--r--spec/features/admin/admin_disables_two_factor_spec.rb2
-rw-r--r--spec/features/admin/admin_uses_repository_checks_spec.rb2
-rw-r--r--spec/features/boards/add_issues_modal_spec.rb2
-rw-r--r--spec/features/boards/boards_spec.rb2
-rw-r--r--spec/features/boards/issue_ordering_spec.rb2
-rw-r--r--spec/features/boards/keyboard_shortcut_spec.rb2
-rw-r--r--spec/features/boards/modal_filter_spec.rb2
-rw-r--r--spec/features/boards/multiple_boards_spec.rb2
-rw-r--r--spec/features/boards/new_issue_spec.rb42
-rw-r--r--spec/features/boards/reload_boards_on_browser_back_spec.rb2
-rw-r--r--spec/features/boards/sidebar_spec.rb2
-rw-r--r--spec/features/boards/sub_group_project_spec.rb2
-rw-r--r--spec/features/commits/user_uses_quick_actions_spec.rb2
-rw-r--r--spec/features/dashboard/todos/target_state_spec.rb2
-rw-r--r--spec/features/groups/board_sidebar_spec.rb2
-rw-r--r--spec/features/groups/board_spec.rb2
-rw-r--r--spec/features/groups/milestone_spec.rb2
-rw-r--r--spec/features/groups/user_browse_projects_group_page_spec.rb2
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/features/instance_statistics/cohorts_spec.rb2
-rw-r--r--spec/features/instance_statistics/instance_statistics_spec.rb2
-rw-r--r--spec/features/issuables/issuable_list_spec.rb2
-rw-r--r--spec/features/issuables/markdown_references/internal_references_spec.rb2
-rw-r--r--spec/features/issuables/markdown_references/jira_spec.rb2
-rw-r--r--spec/features/issuables/user_sees_sidebar_spec.rb2
-rw-r--r--spec/features/issues/bulk_assignment_labels_spec.rb2
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb2
-rw-r--r--spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_emoji_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_hint_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_milestone_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/search_bar_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb2
-rw-r--r--spec/features/issues/form_spec.rb2
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb2
-rw-r--r--spec/features/issues/group_label_sidebar_spec.rb2
-rw-r--r--spec/features/issues/issue_detail_spec.rb2
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb2
-rw-r--r--spec/features/issues/keyboard_shortcut_spec.rb2
-rw-r--r--spec/features/issues/markdown_toolbar_spec.rb2
-rw-r--r--spec/features/issues/move_spec.rb2
-rw-r--r--spec/features/issues/resource_label_events_spec.rb2
-rw-r--r--spec/features/issues/spam_issues_spec.rb2
-rw-r--r--spec/features/issues/todo_spec.rb2
-rw-r--r--spec/features/issues/update_issues_spec.rb2
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb2
-rw-r--r--spec/features/issues/user_creates_confidential_merge_request_spec.rb2
-rw-r--r--spec/features/issues/user_sees_breadcrumb_links_spec.rb2
-rw-r--r--spec/features/issues/user_uses_quick_actions_spec.rb2
-rw-r--r--spec/features/merge_request/user_assigns_themselves_spec.rb2
-rw-r--r--spec/features/merge_request/user_awards_emoji_spec.rb2
-rw-r--r--spec/features/merge_request/user_creates_mr_spec.rb2
-rw-r--r--spec/features/merge_request/user_customizes_merge_commit_message_spec.rb2
-rw-r--r--spec/features/merge_request/user_locks_discussion_spec.rb2
-rw-r--r--spec/features/merge_request/user_merges_immediately_spec.rb2
-rw-r--r--spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb2
-rw-r--r--spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_resolves_conflicts_spec.rb2
-rw-r--r--spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb2
-rw-r--r--spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_breadcrumb_links_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_closing_issues_message_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_deleted_target_branch_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_deployment_widget_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_discussions_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_empty_state_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_pipelines_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_system_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_versions_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_wip_help_message_spec.rb2
-rw-r--r--spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb2
-rw-r--r--spec/features/merge_request/user_toggles_whitespace_changes_spec.rb2
-rw-r--r--spec/features/merge_request/user_uses_quick_actions_spec.rb2
-rw-r--r--spec/features/merge_requests/filters_generic_behavior_spec.rb2
-rw-r--r--spec/features/merge_requests/user_filters_by_assignees_spec.rb2
-rw-r--r--spec/features/merge_requests/user_filters_by_labels_spec.rb2
-rw-r--r--spec/features/merge_requests/user_filters_by_milestones_spec.rb2
-rw-r--r--spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb2
-rw-r--r--spec/features/merge_requests/user_filters_by_target_branch_spec.rb2
-rw-r--r--spec/features/merge_requests/user_lists_merge_requests_spec.rb2
-rw-r--r--spec/features/merge_requests/user_mass_updates_spec.rb2
-rw-r--r--spec/features/milestone_spec.rb2
-rw-r--r--spec/features/milestones/user_creates_milestone_spec.rb2
-rw-r--r--spec/features/milestones/user_deletes_milestone_spec.rb2
-rw-r--r--spec/features/milestones/user_edits_milestone_spec.rb2
-rw-r--r--spec/features/milestones/user_promotes_milestone_spec.rb2
-rw-r--r--spec/features/milestones/user_sees_breadcrumb_links_spec.rb2
-rw-r--r--spec/features/milestones/user_views_milestone_spec.rb2
-rw-r--r--spec/features/milestones/user_views_milestones_spec.rb2
-rw-r--r--spec/features/profiles/account_spec.rb2
-rw-r--r--spec/features/profiles/active_sessions_spec.rb2
-rw-r--r--spec/features/profiles/chat_names_spec.rb2
-rw-r--r--spec/features/profiles/emails_spec.rb2
-rw-r--r--spec/features/profiles/gpg_keys_spec.rb2
-rw-r--r--spec/features/profiles/keys_spec.rb2
-rw-r--r--spec/features/projects/commit/mini_pipeline_graph_spec.rb2
-rw-r--r--spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb2
-rw-r--r--spec/features/projects/settings/lfs_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb2
-rw-r--r--spec/features/projects/show/developer_views_empty_project_instructions_spec.rb2
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb2
-rw-r--r--spec/features/projects/tags/user_edits_tags_spec.rb2
-rw-r--r--spec/features/read_only_spec.rb2
-rw-r--r--spec/features/security/group/internal_access_spec.rb2
-rw-r--r--spec/features/security/group/private_access_spec.rb2
-rw-r--r--spec/features/security/group/public_access_spec.rb2
-rw-r--r--spec/features/snippets/explore_spec.rb2
-rw-r--r--spec/features/snippets/internal_snippet_spec.rb2
-rw-r--r--spec/features/snippets/public_snippets_spec.rb2
-rw-r--r--spec/features/snippets/search_snippets_spec.rb2
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb2
-rw-r--r--spec/features/snippets/user_deletes_snippet_spec.rb2
-rw-r--r--spec/features/snippets/user_edits_snippet_spec.rb2
-rw-r--r--spec/features/snippets/user_snippets_spec.rb2
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_group_spec.rb2
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_profile_spec.rb2
-rw-r--r--spec/features/uploads/user_uploads_file_to_note_spec.rb2
-rw-r--r--spec/features/user_can_display_performance_bar_spec.rb4
-rw-r--r--spec/features/user_sees_revert_modal_spec.rb2
-rw-r--r--spec/fixtures/api/schemas/pipeline.json8
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/release.json1
-rw-r--r--spec/frontend/branches/divergence_graph_spec.js14
-rw-r--r--spec/frontend/clusters/stores/clusters_store_spec.js4
-rw-r--r--spec/frontend/jobs/store/utils_spec.js60
-rw-r--r--spec/frontend/mocks/ce/lib/utils/axios_utils.js3
-rw-r--r--spec/frontend/mocks/mocks_helper_spec.js7
-rw-r--r--spec/frontend/mocks/node/jquery.js4
-rw-r--r--spec/frontend/mocks_spec.js15
-rw-r--r--spec/graphql/features/authorization_spec.rb28
-rw-r--r--spec/graphql/gitlab_schema_spec.rb8
-rw-r--r--spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb2
-rw-r--r--spec/graphql/resolvers/group_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb12
-rw-r--r--spec/graphql/resolvers/namespace_projects_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/project_resolver_spec.rb4
-rw-r--r--spec/helpers/avatars_helper_spec.rb2
-rw-r--r--spec/helpers/boards_helper_spec.rb2
-rw-r--r--spec/helpers/commits_helper_spec.rb2
-rw-r--r--spec/helpers/form_helper_spec.rb2
-rw-r--r--spec/helpers/icons_helper_spec.rb7
-rw-r--r--spec/helpers/import_helper_spec.rb2
-rw-r--r--spec/helpers/page_layout_helper_spec.rb2
-rw-r--r--spec/helpers/profiles_helper_spec.rb2
-rw-r--r--spec/helpers/users_helper_spec.rb2
-rw-r--r--spec/helpers/version_check_helper_spec.rb4
-rw-r--r--spec/javascripts/boards/issue_spec.js6
-rw-r--r--spec/javascripts/flash_spec.js12
-rw-r--r--spec/javascripts/groups/components/app_spec.js3
-rw-r--r--spec/javascripts/groups/service/groups_service_spec.js17
-rw-r--r--spec/javascripts/jobs/components/job_app_spec.js1
-rw-r--r--spec/javascripts/jobs/components/log/line_header_spec.js84
-rw-r--r--spec/javascripts/jobs/components/log/line_number_spec.js40
-rw-r--r--spec/javascripts/jobs/components/log/line_spec.js49
-rw-r--r--spec/javascripts/monitoring/charts/area_spec.js265
-rw-r--r--spec/javascripts/monitoring/components/dashboard_spec.js4
-rw-r--r--spec/lib/banzai/filter/blockquote_fence_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/front_matter_filter_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/description_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/email_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/full_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/gfm_pipeline_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb2
-rw-r--r--spec/lib/gitlab/anonymous_session_spec.rb2
-rw-r--r--spec/lib/gitlab/auth_spec.rb3
-rw-r--r--spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/reset_merge_status_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/project_created_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/project_moved_spec.rb2
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb20
-rw-r--r--spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/favicon_spec.rb8
-rw-r--r--spec/lib/gitlab/file_markdown_link_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/file_type_detection_spec.rb2
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb69
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb2
-rw-r--r--spec/lib/gitlab/gpg/commit_spec.rb2
-rw-r--r--spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb2
-rw-r--r--spec/lib/gitlab/gpg_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb3
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb12
-rw-r--r--spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb6
-rw-r--r--spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml8
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml1
-rw-r--r--spec/lib/gitlab/jwt_authenticatable_spec.rb93
-rw-r--r--spec/lib/gitlab/kubernetes/helm/install_command_spec.rb2
-rw-r--r--spec/lib/gitlab/kubernetes/helm/pod_spec.rb2
-rw-r--r--spec/lib/gitlab/prometheus/metric_group_spec.rb2
-rw-r--r--spec/lib/gitlab/query_limiting/transaction_spec.rb4
-rw-r--r--spec/lib/gitlab/query_limiting_spec.rb9
-rw-r--r--spec/lib/gitlab/sidekiq_config_spec.rb2
-rw-r--r--spec/lib/gitlab/tracing_spec.rb2
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb115
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb51
-rw-r--r--spec/lib/gitlab_spec.rb6
-rw-r--r--spec/mailers/abuse_report_mailer_spec.rb2
-rw-r--r--spec/mailers/email_rejection_mailer_spec.rb2
-rw-r--r--spec/mailers/repository_check_mailer_spec.rb2
-rw-r--r--spec/models/abuse_report_spec.rb2
-rw-r--r--spec/models/active_session_spec.rb2
-rw-r--r--spec/models/appearance_spec.rb2
-rw-r--r--spec/models/blob_spec.rb2
-rw-r--r--spec/models/board_spec.rb2
-rw-r--r--spec/models/ci/pipeline_spec.rb64
-rw-r--r--spec/models/clusters/applications/cert_manager_spec.rb2
-rw-r--r--spec/models/clusters/applications/helm_spec.rb2
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb2
-rw-r--r--spec/models/clusters/applications/jupyter_spec.rb2
-rw-r--r--spec/models/clusters/applications/knative_spec.rb2
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb2
-rw-r--r--spec/models/clusters/applications/runner_spec.rb2
-rw-r--r--spec/models/concerns/blocks_json_serialization_spec.rb2
-rw-r--r--spec/models/concerns/cacheable_attributes_spec.rb4
-rw-r--r--spec/models/concerns/deployable_spec.rb2
-rw-r--r--spec/models/concerns/deployment_platform_spec.rb2
-rw-r--r--spec/models/concerns/routable_spec.rb7
-rw-r--r--spec/models/concerns/sha_attribute_spec.rb4
-rw-r--r--spec/models/concerns/triggerable_hooks_spec.rb2
-rw-r--r--spec/models/conversational_development_index/metric_spec.rb2
-rw-r--r--spec/models/gpg_key_spec.rb2
-rw-r--r--spec/models/gpg_key_subkey_spec.rb2
-rw-r--r--spec/models/gpg_signature_spec.rb2
-rw-r--r--spec/models/hooks/system_hook_spec.rb23
-rw-r--r--spec/models/hooks/web_hook_log_spec.rb2
-rw-r--r--spec/models/internal_id_spec.rb3
-rw-r--r--spec/models/lfs_download_object_spec.rb2
-rw-r--r--spec/models/lfs_file_lock_spec.rb2
-rw-r--r--spec/models/list_spec.rb2
-rw-r--r--spec/models/merge_request/metrics_spec.rb2
-rw-r--r--spec/models/merge_request_diff_commit_spec.rb2
-rw-r--r--spec/models/merge_request_diff_file_spec.rb2
-rw-r--r--spec/models/merge_request_diff_spec.rb14
-rw-r--r--spec/models/merge_request_spec.rb34
-rw-r--r--spec/models/milestone_release_spec.rb36
-rw-r--r--spec/models/milestone_spec.rb20
-rw-r--r--spec/models/note_diff_file_spec.rb2
-rw-r--r--spec/models/notification_setting_spec.rb2
-rw-r--r--spec/models/project_deploy_token_spec.rb2
-rw-r--r--spec/models/project_import_state_spec.rb2
-rw-r--r--spec/models/project_statistics_spec.rb2
-rw-r--r--spec/models/redirect_route_spec.rb2
-rw-r--r--spec/models/release_spec.rb17
-rw-r--r--spec/models/remote_mirror_spec.rb2
-rw-r--r--spec/models/resource_label_event_spec.rb2
-rw-r--r--spec/models/timelog_spec.rb2
-rw-r--r--spec/models/upload_spec.rb2
-rw-r--r--spec/models/user_agent_detail_spec.rb2
-rw-r--r--spec/models/user_callout_spec.rb2
-rw-r--r--spec/policies/board_policy_spec.rb53
-rw-r--r--spec/presenters/ci/pipeline_presenter_spec.rb34
-rw-r--r--spec/presenters/clusterable_presenter_spec.rb9
-rw-r--r--spec/rails_helper.rb1
-rw-r--r--spec/requests/api/graphql/gitlab_schema_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_wip_spec.rb11
-rw-r--r--spec/requests/api/groups_spec.rb16
-rw-r--r--spec/requests/api/internal/base_spec.rb (renamed from spec/requests/api/internal_spec.rb)2
-rw-r--r--spec/requests/api/pages_domains_spec.rb2
-rw-r--r--spec/requests/api/project_snippets_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb2
-rw-r--r--spec/requests/api/snippets_spec.rb2
-rw-r--r--spec/serializers/entity_date_helper_spec.rb22
-rw-r--r--spec/serializers/pipeline_entity_spec.rb6
-rw-r--r--spec/services/audit_event_service_spec.rb12
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb12
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb24
-rw-r--r--spec/services/clusters/applications/check_installation_progress_service_spec.rb6
-rw-r--r--spec/services/clusters/applications/check_uninstall_progress_service_spec.rb8
-rw-r--r--spec/services/groups/transfer_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/project_dashboard_service_spec.rb2
-rw-r--r--spec/services/milestones/destroy_service_spec.rb14
-rw-r--r--spec/services/milestones/find_or_create_service_spec.rb82
-rw-r--r--spec/services/milestones/transfer_service_spec.rb122
-rw-r--r--spec/services/notification_service_spec.rb4
-rw-r--r--spec/services/projects/transfer_service_spec.rb13
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb61
-rw-r--r--spec/services/releases/create_service_spec.rb62
-rw-r--r--spec/services/releases/destroy_service_spec.rb10
-rw-r--r--spec/services/releases/update_service_spec.rb37
-rw-r--r--spec/services/system_hooks_service_spec.rb10
-rw-r--r--spec/services/update_merge_request_metrics_service_spec.rb2
-rw-r--r--spec/spec_helper.rb7
-rw-r--r--spec/support/helpers/graphql_helpers.rb18
-rw-r--r--spec/support/helpers/project_forks_helper.rb2
-rw-r--r--spec/support/helpers/rails_helpers.rb7
-rw-r--r--spec/support/helpers/test_env.rb1
-rw-r--r--spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb2
-rw-r--r--spec/tasks/gitlab/gitaly_rake_spec.rb4
-rw-r--r--spec/uploaders/gitlab_uploader_spec.rb2
-rw-r--r--spec/uploaders/object_storage_spec.rb2
-rw-r--r--spec/uploaders/records_uploads_spec.rb2
-rw-r--r--spec/uploaders/uploader_helper_spec.rb2
-rw-r--r--spec/validators/addressable_url_validator_spec.rb37
-rw-r--r--spec/views/devise/shared/_signin_box.html.haml_spec.rb2
-rw-r--r--spec/views/help/index.html.haml_spec.rb2
-rw-r--r--spec/views/help/instance_configuration.html.haml_spec.rb2
-rw-r--r--spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb8
-rw-r--r--spec/views/projects/settings/operations/show.html.haml_spec.rb1
-rw-r--r--spec/workers/repository_remove_remote_worker_spec.rb2
-rw-r--r--spec/workers/repository_update_remote_mirror_worker_spec.rb2
-rw-r--r--spec/workers/upload_checksum_worker_spec.rb2
-rw-r--r--yarn.lock92
705 files changed, 7338 insertions, 3801 deletions
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 0d73092cfba..0720ea3e056 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -233,22 +233,3 @@ qa-frontend-node:latest:
extends: .qa-frontend-node
image: node:latest
allow_failure: true
-
-jsdoc:
- extends:
- - .default-tags
- - .default-retry
- - .default-cache
- - .except-docs
- variables:
- SETUP_DB: "false"
- stage: post-test
- dependencies: ["compile-assets", "compile-assets pull-cache"]
- script:
- - date
- - yarn run jsdoc || true # ignore exit code
- artifacts:
- name: jsdoc
- expire_in: 31d
- paths:
- - jsdoc/
diff --git a/.gitlab/ci/pages.gitlab-ci.yml b/.gitlab/ci/pages.gitlab-ci.yml
index 5d13a72e224..2de09753cca 100644
--- a/.gitlab/ci/pages.gitlab-ci.yml
+++ b/.gitlab/ci/pages.gitlab-ci.yml
@@ -9,7 +9,7 @@ pages:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
stage: pages
- dependencies: ["coverage", "karma", "gitlab:assets:compile", "jsdoc"]
+ dependencies: ["coverage", "karma", "gitlab:assets:compile"]
script:
- mv public/ .public/
- mkdir public/
@@ -18,7 +18,6 @@ pages:
- mv webpack-report/ public/webpack-report/ || true
- cp .public/assets/application-*.css public/application.css || true
- cp .public/assets/application-*.css.gz public/application.css.gz || true
- - mv jsdoc/ public/jsdoc/ || true
artifacts:
paths:
- public
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml
index ac2a70dda0b..9c021b23db6 100644
--- a/.gitlab/ci/qa.gitlab-ci.yml
+++ b/.gitlab/ci/qa.gitlab-ci.yml
@@ -1,7 +1,6 @@
.package-and-qa-base:
image: ruby:2.6-alpine
stage: qa
- needs: ["build-qa-image", "gitlab:assets:compile pull-cache"]
dependencies: []
variables:
GIT_DEPTH: "1"
@@ -11,24 +10,33 @@
- install_gitlab_gem
- ./scripts/trigger-build omnibus
only:
- - branches@gitlab-org/gitlab-ce
- - branches@gitlab-org/gitlab-ee
- except:
- - master
+ refs:
+ - branches@gitlab-org/gitlab-ce
+ - branches@gitlab-org/gitlab-ee
package-and-qa-manual:
- extends:
- - .package-and-qa-base
- - .except-docs-qa
- when: manual
+ extends: .package-and-qa-base
except:
- - master
- - /(^docs[\/-].+|.+-docs$)/
- - /(^qa[\/-].*|.*-qa$)
+ refs:
+ - master
+ - /(^docs[\/-].+|.+-docs$)/
+ - /(^qa[\/-].*|.*-qa$)/
+ when: manual
+ needs: ["build-qa-image", "gitlab:assets:compile pull-cache"]
+
+package-and-qa-manual:master:
+ extends: .package-and-qa-base
+ only:
+ refs:
+ - master
+ when: manual
+ needs: ["build-qa-image", "gitlab:assets:compile"]
package-and-qa:
extends: .package-and-qa-base
- allow_failure: true
only:
- - /(^qa[\/-].*|.*-qa$)/@gitlab-org/gitlab-ce
- - /(^qa[\/-].*|.*-qa$)/@gitlab-org/gitlab-ee
+ refs:
+ - /(^qa[\/-].*|.*-qa$)/@gitlab-org/gitlab-ce
+ - /(^qa[\/-].*|.*-qa$)/@gitlab-org/gitlab-ee
+ needs: ["build-qa-image", "gitlab:assets:compile pull-cache"]
+ allow_failure: true
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 3415f1b6ab4..6695404653c 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -22,7 +22,9 @@
- source scripts/utils.sh
.review-docker:
- extends: .review-base
+ extends:
+ - .default-tags
+ - .default-retry
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine
services:
- docker:19.03.0-dind
@@ -36,7 +38,13 @@
QA_IMAGE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab/${CI_PROJECT_NAME}-qa:${CI_COMMIT_REF_SLUG}"
build-qa-image:
- extends: .review-docker
+ extends:
+ - .review-docker
+ - .except-docs
+ only:
+ refs:
+ - branches@gitlab-org/gitlab-ce
+ - branches@gitlab-org/gitlab-ee
stage: test
script:
- time docker build --cache-from ${LATEST_QA_IMAGE} --tag ${QA_IMAGE} --file ./qa/Dockerfile ./
@@ -120,11 +128,14 @@ review-stop:
- source utils.sh
- source review-apps.sh
script:
- - delete
- artifacts: {}
+ - delete_release
+ artifacts:
+ paths: []
.review-qa-base:
- extends: .review-docker
+ extends:
+ - .review-docker
+ - .review-only
retry: 2
stage: qa
variables:
diff --git a/.gitlab/ci/yaml.gitlab-ci.yml b/.gitlab/ci/yaml.gitlab-ci.yml
index 3e107b475c9..dd61cb3f035 100644
--- a/.gitlab/ci/yaml.gitlab-ci.yml
+++ b/.gitlab/ci/yaml.gitlab-ci.yml
@@ -4,6 +4,7 @@ lint-ci-gitlab:
extends:
- .default-tags
- .default-retry
+ - .except-docs
image: sdesbure/yamllint:latest
dependencies: []
script:
diff --git a/.rubocop.yml b/.rubocop.yml
index a20924c21b7..f24cbb6ce92 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -264,8 +264,6 @@ RSpec/EnvAssignment:
Exclude:
- 'spec/**/fast_spec_helper.rb'
- 'ee/spec/**/fast_spec_helper.rb'
- - 'spec/**/rails_helper.rb'
- - 'ee/spec/**/rails_helper.rb'
- 'spec/**/spec_helper.rb'
- 'ee/spec/**/spec_helper.rb'
RSpec/BeSuccessMatcher:
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 3898206e3b5..f1f8ff6e862 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -218,7 +218,7 @@ Lint/UriEscapeUnescape:
- 'app/models/project_services/drone_ci_service.rb'
- 'spec/lib/google_api/auth_spec.rb'
- 'spec/requests/api/files_spec.rb'
- - 'spec/requests/api/internal_spec.rb'
+ - 'spec/requests/api/internal/base_spec.rb'
# Offense count: 1
# Configuration parameters: CheckForMethodsWithNoSideEffects.
@@ -570,11 +570,6 @@ Style/EmptyMethod:
Style/Encoding:
Enabled: false
-# Offense count: 2
-Style/EvalWithLocation:
- Exclude:
- - 'app/models/service.rb'
-
# Offense count: 203
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 3c40359d3dc..a13e7b9c87e 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-9.4.2
+10.0.0
diff --git a/Gemfile b/Gemfile
index aa17e01b34d..3e3a8c5dde2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -83,7 +83,7 @@ gem 'grape-entity', '~> 0.7.1'
gem 'rack-cors', '~> 1.0.0', require: 'rack/cors'
# GraphQL API
-gem 'graphql', '= 1.8.4'
+gem 'graphql', '~> 1.9.11'
gem 'graphiql-rails', '~> 1.4.10'
gem 'apollo_upload_server', '~> 2.0.0.beta3'
gem 'graphql-docs', '~> 1.6.0', group: [:development, :test]
@@ -171,7 +171,7 @@ gem 'acts-as-taggable-on', '~> 6.0'
gem 'sidekiq', '~> 5.2.7'
gem 'sidekiq-cron', '~> 1.0'
gem 'redis-namespace', '~> 1.6.0'
-gem 'gitlab-sidekiq-fetcher', '0.5.1', require: 'sidekiq-reliable-fetch'
+gem 'gitlab-sidekiq-fetcher', '0.5.2', require: 'sidekiq-reliable-fetch'
# Cron Parser
gem 'fugit', '~> 1.2.1'
@@ -216,6 +216,7 @@ gem 'hipchat', '~> 1.5.0'
# Jira integration
gem 'jira-ruby', '~> 1.7'
+gem 'atlassian-jwt', '~> 0.2.0'
# Flowdock integration
gem 'flowdock', '~> 0.7'
@@ -310,7 +311,7 @@ group :metrics do
gem 'influxdb', '~> 0.2', require: false
# Prometheus
- gem 'prometheus-client-mmap', '~> 0.9.8'
+ gem 'prometheus-client-mmap', '~> 0.9.9'
gem 'raindrops', '~> 0.18'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 0803cf7f752..6add217bc32 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -321,7 +321,7 @@ GEM
gitlab-markup (1.7.0)
gitlab-peek (0.0.1)
railties (>= 4.0.0)
- gitlab-sidekiq-fetcher (0.5.1)
+ gitlab-sidekiq-fetcher (0.5.2)
sidekiq (~> 5)
gitlab-styles (2.8.0)
rubocop (~> 0.69.0)
@@ -377,7 +377,7 @@ GEM
graphiql-rails (1.4.10)
railties
sprockets-rails
- graphql (1.8.4)
+ graphql (1.9.11)
graphql-docs (1.6.0)
commonmarker (~> 0.16)
escape_utils (~> 1.2)
@@ -650,7 +650,7 @@ GEM
parser
unparser
procto (0.0.3)
- prometheus-client-mmap (0.9.8)
+ prometheus-client-mmap (0.9.9)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
@@ -1028,6 +1028,7 @@ DEPENDENCIES
asciidoctor (~> 2.0.10)
asciidoctor-include-ext (~> 0.3.1)
asciidoctor-plantuml (= 0.0.9)
+ atlassian-jwt (~> 0.2.0)
attr_encrypted (~> 3.1.0)
awesome_print
babosa (~> 1.0.2)
@@ -1097,7 +1098,7 @@ DEPENDENCIES
gitlab-labkit (~> 0.5)
gitlab-markup (~> 1.7.0)
gitlab-peek (~> 0.0.1)
- gitlab-sidekiq-fetcher (= 0.5.1)
+ gitlab-sidekiq-fetcher (= 0.5.2)
gitlab-styles (~> 2.7)
gitlab_omniauth-ldap (~> 2.1.1)
gon (~> 6.2)
@@ -1109,7 +1110,7 @@ DEPENDENCIES
grape-path-helpers (~> 1.1)
grape_logging (~> 1.7)
graphiql-rails (~> 1.4.10)
- graphql (= 1.8.4)
+ graphql (~> 1.9.11)
graphql-docs (~> 1.6.0)
grpc (~> 1.19.0)
haml_lint (~> 0.31.0)
@@ -1169,7 +1170,7 @@ DEPENDENCIES
org-ruby (~> 0.9.12)
pg (~> 1.1)
premailer-rails (~> 1.9.7)
- prometheus-client-mmap (~> 0.9.8)
+ prometheus-client-mmap (~> 0.9.9)
pry-byebug (~> 3.5.1)
pry-rails (~> 0.3.4)
puma (~> 3.12)
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index 4180023b7db..f9284266b72 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -114,7 +114,7 @@ export default {
name="issue_title"
autocomplete="off"
/>
- <project-select v-if="groupId" :group-id="groupId" />
+ <project-select v-if="groupId" :group-id="groupId" :list="list" />
<div class="clearfix prepend-top-10">
<gl-button
ref="submit-button"
diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue
index e8d25e84be1..e5ebb887ce0 100644
--- a/app/assets/javascripts/boards/components/project_select.vue
+++ b/app/assets/javascripts/boards/components/project_select.vue
@@ -6,6 +6,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../eventhub';
import Api from '../../api';
+import { featureAccessLevel } from '~/pages/projects/shared/permissions/constants';
export default {
name: 'BoardProjectSelect',
@@ -19,6 +20,10 @@ export default {
required: true,
default: 0,
},
+ list: {
+ type: Object,
+ required: true,
+ },
},
data() {
return {
@@ -49,6 +54,12 @@ export default {
selectable: true,
data: (term, callback) => {
this.loading = true;
+ const additionalAttrs = {};
+
+ if (this.list.type && this.list.type !== 'backlog') {
+ additionalAttrs.min_access_level = featureAccessLevel.EVERYONE;
+ }
+
return Api.groupProjects(
this.groupId,
term,
@@ -56,6 +67,7 @@ export default {
with_issues_enabled: true,
with_shared: false,
include_subgroups: true,
+ ...additionalAttrs,
},
projects => {
this.loading = false;
diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js
index 9069b35db9a..086340105b7 100644
--- a/app/assets/javascripts/boards/models/issue.js
+++ b/app/assets/javascripts/boards/models/issue.js
@@ -3,7 +3,7 @@
/* global ListMilestone */
/* global ListAssignee */
-import Vue from 'vue';
+import axios from '~/lib/utils/axios_utils';
import './label';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import IssueProject from './project';
@@ -133,7 +133,7 @@ class ListIssue {
}
const projectPath = this.project ? this.project.path : '';
- return Vue.http.patch(`${this.path}.json`, data).then(({ body = {} } = {}) => {
+ return axios.patch(`${this.path}.json`, data).then(({ data: body = {} } = {}) => {
/**
* Since post implementation of Scoped labels, server can reject
* same key-ed labels. To keep the UI and server Model consistent,
diff --git a/app/assets/javascripts/branches/divergence_graph.js b/app/assets/javascripts/branches/divergence_graph.js
index 7dbaf984acf..303735a1807 100644
--- a/app/assets/javascripts/branches/divergence_graph.js
+++ b/app/assets/javascripts/branches/divergence_graph.js
@@ -25,6 +25,11 @@ export default endpoint => {
const names = [...document.querySelectorAll('.js-branch-item')].map(
({ dataset }) => dataset.name,
);
+
+ if (names.length === 0) {
+ return true;
+ }
+
return axios
.get(endpoint, {
params: { names },
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 5f5c8044b49..1f213d5aaf2 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -14,6 +14,8 @@ import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue';
import setupToggleButtons from '../toggle_buttons';
+const Environments = () => import('ee_component/clusters/components/environments.vue');
+
Vue.use(GlToast);
/**
@@ -44,6 +46,9 @@ export default class Clusters {
helpPath,
ingressHelpPath,
ingressDnsHelpPath,
+ environmentsHelpPath,
+ clustersHelpPath,
+ deployBoardsHelpPath,
clusterId,
} = document.querySelector('.js-edit-cluster-form').dataset;
@@ -52,7 +57,14 @@ export default class Clusters {
this.clusterBannerDismissedKey = `cluster_${this.clusterId}_banner_dismissed`;
this.store = new ClustersStore();
- this.store.setHelpPaths(helpPath, ingressHelpPath, ingressDnsHelpPath);
+ this.store.setHelpPaths(
+ helpPath,
+ ingressHelpPath,
+ ingressDnsHelpPath,
+ environmentsHelpPath,
+ clustersHelpPath,
+ deployBoardsHelpPath,
+ );
this.store.setManagePrometheusPath(managePrometheusPath);
this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason);
@@ -95,11 +107,12 @@ export default class Clusters {
setupToggleButtons(toggleButtonsContainer);
}
this.initApplications(clusterType);
+ this.initEnvironments();
this.updateContainer(null, this.store.state.status, this.store.state.statusReason);
this.addListeners();
- if (statusPath) {
+ if (statusPath && !this.environments) {
this.initPolling();
}
}
@@ -131,6 +144,34 @@ export default class Clusters {
});
}
+ initEnvironments() {
+ const { store } = this;
+ const el = document.querySelector('#js-cluster-environments');
+
+ if (!el) {
+ return;
+ }
+
+ this.environments = new Vue({
+ el,
+ data() {
+ return {
+ state: store.state,
+ };
+ },
+ render(createElement) {
+ return createElement(Environments, {
+ props: {
+ environments: this.state.environments,
+ environmentsHelpPath: this.state.environmentsHelpPath,
+ clustersHelpPath: this.state.clustersHelpPath,
+ deployBoardsHelpPath: this.state.deployBoardsHelpPath,
+ },
+ });
+ },
+ });
+ }
+
static initDismissableCallout() {
const callout = document.querySelector('.js-cluster-security-warning');
PersistentUserCallout.factory(callout);
@@ -390,6 +431,10 @@ export default class Clusters {
this.poll.stop();
}
+ if (this.environments) {
+ this.environments.$destroy();
+ }
+
this.applications.$destroy();
}
}
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index 772f16cab4e..83533c88f69 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -32,6 +32,9 @@ export default class ClusterStore {
this.state = {
helpPath: null,
ingressHelpPath: null,
+ environmentsHelpPath: null,
+ clustersHelpPath: null,
+ deployBoardsHelpPath: null,
status: null,
rbac: false,
statusReason: null,
@@ -80,13 +83,24 @@ export default class ClusterStore {
updateFailed: false,
},
},
+ environments: [],
};
}
- setHelpPaths(helpPath, ingressHelpPath, ingressDnsHelpPath) {
+ setHelpPaths(
+ helpPath,
+ ingressHelpPath,
+ ingressDnsHelpPath,
+ environmentsHelpPath,
+ clustersHelpPath,
+ deployBoardsHelpPath,
+ ) {
this.state.helpPath = helpPath;
this.state.ingressHelpPath = ingressHelpPath;
this.state.ingressDnsHelpPath = ingressDnsHelpPath;
+ this.state.environmentsHelpPath = environmentsHelpPath;
+ this.state.clustersHelpPath = clustersHelpPath;
+ this.state.deployBoardsHelpPath = deployBoardsHelpPath;
}
setManagePrometheusPath(managePrometheusPath) {
@@ -191,4 +205,17 @@ export default class ClusterStore {
}
});
}
+
+ updateEnvironments(environments = []) {
+ this.state.environments = environments.map(environment => ({
+ name: environment.name,
+ project: environment.project,
+ environmentPath: environment.environment_path,
+ lastDeployment: environment.last_deployment,
+ rolloutStatus: {
+ instances: environment.rollout_status ? environment.rollout_status.instances : [],
+ },
+ updatedAt: environment.updatedAt,
+ }));
+ }
}
diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js
index c2397842125..660f0f0ba3e 100644
--- a/app/assets/javascripts/flash.js
+++ b/app/assets/javascripts/flash.js
@@ -1,4 +1,5 @@
import _ from 'underscore';
+import { spriteIcon } from './lib/utils/common_utils';
const hideFlash = (flashEl, fadeTransition = true) => {
if (fadeTransition) {
@@ -35,16 +36,11 @@ const createAction = config => `
</a>
`;
-const createFlashEl = (message, type, isFixedLayout = false) => `
- <div
- class="flash-${type}"
- >
- <div
- class="flash-text ${
- isFixedLayout ? 'container-fluid container-limited limit-container-width' : ''
- }"
- >
+const createFlashEl = (message, type) => `
+ <div class="flash-content flash-${type} rounded">
+ <div class="flash-text">
${_.escape(message)}
+ ${spriteIcon('close', 'close-icon')}
</div>
</div>
`;
@@ -76,15 +72,10 @@ const createFlash = function createFlash(
addBodyClass = false,
) {
const flashContainer = parent.querySelector('.flash-container');
- const navigation = parent.querySelector('.content');
if (!flashContainer) return null;
- const isFixedLayout = navigation
- ? navigation.parentNode.classList.contains('container-limited')
- : true;
-
- flashContainer.innerHTML = createFlashEl(message, type, isFixedLayout);
+ flashContainer.innerHTML = createFlashEl(message, type);
const flashEl = flashContainer.querySelector(`.flash-${type}`);
removeFlashClickListener(flashEl, fadeTransition);
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index aa50fd8ff62..8d2dac47ff2 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -95,10 +95,8 @@ export default {
if (updatePagination) {
this.updatePagination(res.headers);
}
-
- return res;
+ return res.data;
})
- .then(res => res.json())
.catch(() => {
this.isLoading = false;
$.scrollTo(0);
@@ -190,11 +188,10 @@ export default {
this.targetGroup.isBeingRemoved = true;
this.service
.leaveGroup(this.targetGroup.leavePath)
- .then(res => res.json())
.then(res => {
$.scrollTo(0);
this.store.removeGroup(this.targetGroup, this.targetParentGroup);
- Flash(res.notice, 'notice');
+ Flash(res.data.notice, 'notice');
})
.catch(err => {
let message = COMMON_STR.FAILURE;
diff --git a/app/assets/javascripts/groups/service/groups_service.js b/app/assets/javascripts/groups/service/groups_service.js
index b79ba291463..790b581a7c0 100644
--- a/app/assets/javascripts/groups/service/groups_service.js
+++ b/app/assets/javascripts/groups/service/groups_service.js
@@ -1,40 +1,39 @@
-import Vue from 'vue';
-import '../../vue_shared/vue_resource_interceptor';
+import axios from '~/lib/utils/axios_utils';
export default class GroupsService {
constructor(endpoint) {
- this.groups = Vue.resource(endpoint);
+ this.endpoint = endpoint;
}
getGroups(parentId, page, filterGroups, sort, archived) {
- const data = {};
+ const params = {};
if (parentId) {
- data.parent_id = parentId;
+ params.parent_id = parentId;
} else {
// Do not send the following param for sub groups
if (page) {
- data.page = page;
+ params.page = page;
}
if (filterGroups) {
- data.filter = filterGroups;
+ params.filter = filterGroups;
}
if (sort) {
- data.sort = sort;
+ params.sort = sort;
}
if (archived) {
- data.archived = archived;
+ params.archived = archived;
}
}
- return this.groups.get(data);
+ return axios.get(this.endpoint, { params });
}
// eslint-disable-next-line class-methods-use-this
leaveGroup(endpoint) {
- return Vue.http.delete(endpoint);
+ return axios.delete(endpoint);
}
}
diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue
index ad1072366f3..c7d4d7c4b9b 100644
--- a/app/assets/javascripts/jobs/components/job_app.vue
+++ b/app/assets/javascripts/jobs/components/job_app.vue
@@ -83,6 +83,11 @@ export default {
type: String,
required: true,
},
+ subscriptionsMoreMinutesUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
computed: {
...mapState([
@@ -265,6 +270,7 @@ export default {
:quota-limit="job.runners.quota.limit"
:runners-path="runnerHelpUrl"
:project-path="projectPath"
+ :subscriptions-more-minutes-url="subscriptionsMoreMinutesUrl"
/>
<environments-block
diff --git a/app/assets/javascripts/jobs/components/log/line.vue b/app/assets/javascripts/jobs/components/log/line.vue
new file mode 100644
index 00000000000..86d0fcc3b74
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/log/line.vue
@@ -0,0 +1,28 @@
+<script>
+import LineNumber from './line_number.vue';
+
+export default {
+ components: {
+ LineNumber,
+ },
+ props: {
+ line: {
+ type: Object,
+ required: true,
+ },
+ path: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="line">
+ <line-number :line-number="line.lineNumber" :path="path" />
+ <span v-for="(content, i) in line.content" :key="i" class="line-text" :class="content.style">{{
+ content.text
+ }}</span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/jobs/components/log/line_header.vue b/app/assets/javascripts/jobs/components/log/line_header.vue
new file mode 100644
index 00000000000..4ec212d2333
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/log/line_header.vue
@@ -0,0 +1,45 @@
+<script>
+import Icon from '~/vue_shared/components/icon.vue';
+import LineNumber from './line_number.vue';
+
+export default {
+ components: {
+ Icon,
+ LineNumber,
+ },
+ props: {
+ line: {
+ type: Object,
+ required: true,
+ },
+ isClosed: {
+ type: Boolean,
+ required: true,
+ },
+ path: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ iconName() {
+ return this.isClosed ? 'angle-right' : 'angle-down';
+ },
+ },
+ methods: {
+ handleOnClick() {
+ this.$emit('toggleLine');
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="line collapsible-line" role="button" @click="handleOnClick">
+ <icon :name="iconName" class="arrow" />
+ <line-number :line-number="line.lineNumber" :path="path" />
+ <span v-for="(content, i) in line.content" :key="i" class="line-text" :class="content.style">{{
+ content.text
+ }}</span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/jobs/components/log/line_number.vue b/app/assets/javascripts/jobs/components/log/line_number.vue
new file mode 100644
index 00000000000..e06836e2e97
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/log/line_number.vue
@@ -0,0 +1,52 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlLink,
+ },
+ props: {
+ lineNumber: {
+ type: Number,
+ required: true,
+ },
+ path: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ /**
+ * Builds the url for each line number
+ *
+ * @returns {String}
+ */
+ buildLineNumber() {
+ return `${this.path}#${this.lineNumberId}`;
+ },
+ /**
+ * Array indexes start with 0, so we add 1
+ * to create the line number
+ *
+ * @returns {Number} the line number
+ */
+ parsedLineNumber() {
+ return this.lineNumber + 1;
+ },
+
+ /**
+ * Creates the anchor for each link
+ *
+ * @returns {String}
+ */
+ lineNumberId() {
+ return `L${this.parsedLineNumber}`;
+ },
+ },
+};
+</script>
+<template>
+ <gl-link :id="lineNumberId" class="line-number" :href="buildLineNumber">{{
+ parsedLineNumber
+ }}</gl-link>
+</template>
diff --git a/app/assets/javascripts/jobs/index.js b/app/assets/javascripts/jobs/index.js
index add7f9b710a..9c35534523e 100644
--- a/app/assets/javascripts/jobs/index.js
+++ b/app/assets/javascripts/jobs/index.js
@@ -15,6 +15,7 @@ export default () => {
runnerHelpUrl,
runnerSettingsUrl,
variablesSettingsUrl,
+ subscriptionsMoreMinutesUrl,
endpoint,
pagePath,
logState,
@@ -28,6 +29,7 @@ export default () => {
runnerHelpUrl,
runnerSettingsUrl,
variablesSettingsUrl,
+ subscriptionsMoreMinutesUrl,
endpoint,
pagePath,
logState,
diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/jobs/store/utils.js
new file mode 100644
index 00000000000..de7de92ed2e
--- /dev/null
+++ b/app/assets/javascripts/jobs/store/utils.js
@@ -0,0 +1,40 @@
+/**
+ * Parses the job log content into a structure usable by the template
+ *
+ * For collaspible lines (section_header = true):
+ * - creates a new array to hold the lines that are collpasible,
+ * - adds a isClosed property to handle toggle
+ * - adds a isHeader property to handle template logic
+ * For each line:
+ * - adds the index as lineNumber
+ *
+ * @param {Array} lines
+ * @returns {Array}
+ */
+export default (lines = []) =>
+ lines.reduce((acc, line, index) => {
+ if (line.section_header) {
+ acc.push({
+ isClosed: true,
+ isHeader: true,
+ line: {
+ ...line,
+ lineNumber: index,
+ },
+
+ lines: [],
+ });
+ } else if (acc.length && acc[acc.length - 1].isHeader) {
+ acc[acc.length - 1].lines.push({
+ ...line,
+ lineNumber: index,
+ });
+ } else {
+ acc.push({
+ ...line,
+ lineNumber: index,
+ });
+ }
+
+ return acc;
+ }, []);
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue
deleted file mode 100644
index cac10474d06..00000000000
--- a/app/assets/javascripts/monitoring/components/charts/area.vue
+++ /dev/null
@@ -1,304 +0,0 @@
-<script>
-import { __ } from '~/locale';
-import { GlLink } from '@gitlab/ui';
-import { GlAreaChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
-import dateFormat from 'dateformat';
-import { debounceByAnimationFrame, roundOffFloat } from '~/lib/utils/common_utils';
-import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
-import Icon from '~/vue_shared/components/icon.vue';
-import { chartHeight, graphTypes, lineTypes } from '../../constants';
-import { makeDataSeries } from '~/helpers/monitor_helper';
-import { graphDataValidatorForValues } from '../../utils';
-
-let debouncedResize;
-
-// TODO: Remove this component in favor of the more general time_series.vue
-// Please port all changes here to time_series.vue as well.
-
-export default {
- components: {
- GlAreaChart,
- GlChartSeriesLabel,
- GlLink,
- Icon,
- },
- inheritAttrs: false,
- props: {
- graphData: {
- type: Object,
- required: true,
- validator: graphDataValidatorForValues.bind(null, false),
- },
- containerWidth: {
- type: Number,
- required: true,
- },
- deploymentData: {
- type: Array,
- required: false,
- default: () => [],
- },
- projectPath: {
- type: String,
- required: false,
- default: () => '',
- },
- showBorder: {
- type: Boolean,
- required: false,
- default: () => false,
- },
- singleEmbed: {
- type: Boolean,
- required: false,
- default: false,
- },
- thresholds: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- data() {
- return {
- tooltip: {
- title: '',
- content: [],
- commitUrl: '',
- isDeployment: false,
- sha: '',
- },
- width: 0,
- height: chartHeight,
- svgs: {},
- primaryColor: null,
- };
- },
- computed: {
- chartData() {
- // Transforms & supplements query data to render appropriate labels & styles
- // Input: [{ queryAttributes1 }, { queryAttributes2 }]
- // Output: [{ seriesAttributes1 }, { seriesAttributes2 }]
- return this.graphData.queries.reduce((acc, query) => {
- const { appearance } = query;
- const lineType =
- appearance && appearance.line && appearance.line.type
- ? appearance.line.type
- : lineTypes.default;
- const lineWidth =
- appearance && appearance.line && appearance.line.width
- ? appearance.line.width
- : undefined;
-
- const series = makeDataSeries(query.result, {
- name: this.formatLegendLabel(query),
- lineStyle: {
- type: lineType,
- width: lineWidth,
- },
- areaStyle: {
- opacity:
- appearance && appearance.area && typeof appearance.area.opacity === 'number'
- ? appearance.area.opacity
- : undefined,
- },
- });
-
- return acc.concat(series);
- }, []);
- },
- chartOptions() {
- return {
- xAxis: {
- name: __('Time'),
- type: 'time',
- axisLabel: {
- formatter: date => dateFormat(date, 'h:MM TT'),
- },
- axisPointer: {
- snap: true,
- },
- },
- yAxis: {
- name: this.yAxisLabel,
- axisLabel: {
- formatter: num => roundOffFloat(num, 3).toString(),
- },
- },
- series: this.scatterSeries,
- dataZoom: [this.dataZoomConfig],
- };
- },
- dataZoomConfig() {
- const handleIcon = this.svgs['scroll-handle'];
-
- return handleIcon ? { handleIcon } : {};
- },
- earliestDatapoint() {
- return this.chartData.reduce((acc, series) => {
- const { data } = series;
- const { length } = data;
- if (!length) {
- return acc;
- }
-
- const [first] = data[0];
- const [last] = data[length - 1];
- const seriesEarliest = first < last ? first : last;
-
- return seriesEarliest < acc || acc === null ? seriesEarliest : acc;
- }, null);
- },
- isMultiSeries() {
- return this.tooltip.content.length > 1;
- },
- recentDeployments() {
- return this.deploymentData.reduce((acc, deployment) => {
- if (deployment.created_at >= this.earliestDatapoint) {
- acc.push({
- id: deployment.id,
- createdAt: deployment.created_at,
- sha: deployment.sha,
- commitUrl: `${this.projectPath}/commit/${deployment.sha}`,
- tag: deployment.tag,
- tagUrl: deployment.tag ? `${this.tagsPath}/${deployment.ref.name}` : null,
- ref: deployment.ref.name,
- showDeploymentFlag: false,
- });
- }
-
- return acc;
- }, []);
- },
- scatterSeries() {
- return {
- type: graphTypes.deploymentData,
- data: this.recentDeployments.map(deployment => [deployment.createdAt, 0]),
- symbol: this.svgs.rocket,
- symbolSize: 14,
- itemStyle: {
- color: this.primaryColor,
- },
- };
- },
- yAxisLabel() {
- return `${this.graphData.y_label}`;
- },
- },
- watch: {
- containerWidth: 'onResize',
- },
- beforeDestroy() {
- window.removeEventListener('resize', debouncedResize);
- },
- created() {
- debouncedResize = debounceByAnimationFrame(this.onResize);
- window.addEventListener('resize', debouncedResize);
- this.setSvg('rocket');
- this.setSvg('scroll-handle');
- },
- methods: {
- formatLegendLabel(query) {
- return `${query.label}`;
- },
- formatTooltipText(params) {
- this.tooltip.title = dateFormat(params.value, 'dd mmm yyyy, h:MMTT');
- this.tooltip.content = [];
- params.seriesData.forEach(seriesData => {
- this.tooltip.isDeployment = seriesData.componentSubType === graphTypes.deploymentData;
- if (this.tooltip.isDeployment) {
- const [deploy] = this.recentDeployments.filter(
- deployment => deployment.createdAt === seriesData.value[0],
- );
- this.tooltip.sha = deploy.sha.substring(0, 8);
- this.tooltip.commitUrl = deploy.commitUrl;
- } else {
- const { seriesName, color } = seriesData;
- // seriesData.value contains the chart's [x, y] value pair
- // seriesData.value[1] is threfore the chart y value
- const value = seriesData.value[1].toFixed(3);
-
- this.tooltip.content.push({
- name: seriesName,
- value,
- color,
- });
- }
- });
- },
- setSvg(name) {
- getSvgIconPathContent(name)
- .then(path => {
- if (path) {
- this.$set(this.svgs, name, `path://${path}`);
- }
- })
- .catch(() => {});
- },
- onChartUpdated(chart) {
- [this.primaryColor] = chart.getOption().color;
- },
- onResize() {
- if (!this.$refs.areaChart) return;
- const { width } = this.$refs.areaChart.$el.getBoundingClientRect();
- this.width = width;
- },
- },
-};
-</script>
-
-<template>
- <div
- class="prometheus-graph col-12"
- :class="[showBorder ? 'p-2' : 'p-0', { 'col-lg-6': !singleEmbed }]"
- >
- <div :class="{ 'prometheus-graph-embed w-100 p-3': showBorder }">
- <div class="prometheus-graph-header">
- <h5 ref="graphTitle" class="prometheus-graph-title">{{ graphData.title }}</h5>
- <div ref="graphWidgets" class="prometheus-graph-widgets"><slot></slot></div>
- </div>
- <gl-area-chart
- ref="areaChart"
- v-bind="$attrs"
- :data="chartData"
- :option="chartOptions"
- :format-tooltip-text="formatTooltipText"
- :thresholds="thresholds"
- :width="width"
- :height="height"
- @updated="onChartUpdated"
- >
- <template v-if="tooltip.isDeployment">
- <template slot="tooltipTitle">
- {{ __('Deployed') }}
- </template>
- <div slot="tooltipContent" class="d-flex align-items-center">
- <icon name="commit" class="mr-2" />
- <gl-link :href="tooltip.commitUrl">{{ tooltip.sha }}</gl-link>
- </div>
- </template>
- <template v-else>
- <template slot="tooltipTitle">
- <div class="text-nowrap">
- {{ tooltip.title }}
- </div>
- </template>
- <template slot="tooltipContent">
- <div
- v-for="(content, key) in tooltip.content"
- :key="key"
- class="d-flex justify-content-between"
- >
- <gl-chart-series-label :color="isMultiSeries ? content.color : ''">
- {{ content.name }}
- </gl-chart-series-label>
- <div class="prepend-left-32">
- {{ content.value }}
- </div>
- </div>
- </template>
- </template>
- </gl-area-chart>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
index 820f0f7f12d..0d377eb9c68 100644
--- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
+++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
@@ -5,9 +5,10 @@ import { parseBoolean } from '~/lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => {
const twoFactorNode = document.querySelector('.js-two-factor-auth');
const skippable = parseBoolean(twoFactorNode.dataset.twoFactorSkippable);
+
if (skippable) {
const button = `<a class="btn btn-sm btn-warning float-right" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>`;
- const flashAlert = document.querySelector('.flash-alert .container-fluid');
+ const flashAlert = document.querySelector('.flash-alert');
if (flashAlert) flashAlert.insertAdjacentHTML('beforeend', button);
}
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index 332b6811af6..33e9a8e9d56 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -73,13 +73,6 @@ export default class Project {
.remove();
return e.preventDefault();
});
- $('.hide-shared-runner-limit-message').on('click', function(e) {
- var $alert = $(this).parents('.shared-runner-quota-message');
- var scope = $alert.data('scope');
- Cookies.set('hide_shared_runner_quota_message', 'false', { path: scope });
- $alert.remove();
- e.preventDefault();
- });
$('.hide-auto-devops-implicitly-enabled-banner').on('click', function(e) {
const projectId = $(this).data('project-id');
const cookieKey = `hide_auto_devops_implicitly_enabled_banner_${projectId}`;
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/constants.js b/app/assets/javascripts/pages/projects/shared/permissions/constants.js
index 73269c6f3ba..6771391254e 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/constants.js
+++ b/app/assets/javascripts/pages/projects/shared/permissions/constants.js
@@ -16,7 +16,7 @@ export const visibilityLevelDescriptions = {
),
};
-const featureAccessLevel = {
+export const featureAccessLevel = {
NOT_ENABLED: 0,
PROJECT_MEMBERS: 10,
EVERYONE: 20,
diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss
index 96f6d02a68f..af05d069f97 100644
--- a/app/assets/stylesheets/framework/flash.scss
+++ b/app/assets/stylesheets/framework/flash.scss
@@ -1,3 +1,5 @@
+$notification-box-shadow-color: rgba(0, 0, 0, 0.25);
+
.flash-container {
cursor: pointer;
margin: 0;
@@ -6,12 +8,32 @@
position: relative;
z-index: 1;
+ &.sticky {
+ position: sticky;
+ position: -webkit-sticky;
+ top: $flash-container-top;
+ z-index: 200;
+
+ .flash-content {
+ box-shadow: 0 2px 4px 0 $notification-box-shadow-color;
+ }
+ }
+
+ .close-icon {
+ width: 16px;
+ height: 16px;
+ position: absolute;
+ right: $gl-padding;
+ top: $gl-padding;
+ }
+
.flash-notice,
.flash-alert,
.flash-success,
.flash-warning {
border-radius: $border-radius-default;
color: $white-light;
+ padding-right: $gl-padding * 2;
.container-fluid,
.container-fluid.container-limited {
@@ -97,3 +119,28 @@
}
}
}
+
+.gl-browser-ie .flash-container {
+ position: fixed;
+ max-width: $limited-layout-width;
+ left: 50%;
+
+ .flash-alert {
+ position: relative;
+ left: -50%;
+ }
+}
+
+.with-system-header .flash-container {
+ top: $flash-container-top + $system-header-height;
+}
+
+.with-performance-bar {
+ .flash-container {
+ top: $flash-container-top + $performance-bar-height;
+ }
+
+ &.with-system-header .flash-container {
+ top: $flash-container-top + $performance-bar-height + $system-header-height;
+ }
+}
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 97cb9d90ff0..7205324e86f 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -29,6 +29,15 @@ body {
}
}
+.container-fluid {
+ &.limit-container-width {
+ .flash-container.sticky {
+ max-width: $limited-layout-width;
+ margin: 0 auto;
+ }
+ }
+}
+
.content-wrapper {
margin-top: $header-height;
padding-bottom: 100px;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 7a3fd2adfbb..15a779dde1d 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -377,6 +377,7 @@ $performance-bar-height: 35px;
$system-header-height: 16px;
$system-footer-height: $system-header-height;
$flash-height: 52px;
+$flash-container-top: 48px;
$context-header-height: 60px;
$breadcrumb-min-height: 48px;
$home-panel-title-row-height: 64px;
diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss
index 255383d89c8..88d6b0d3746 100644
--- a/app/assets/stylesheets/pages/clusters.scss
+++ b/app/assets/stylesheets/pages/clusters.scss
@@ -154,3 +154,12 @@
}
}
}
+
+.cluster-deployments-warning {
+ color: $orange-600;
+}
+
+.badge.pods-badge {
+ color: $black;
+ font-weight: $gl-font-weight-bold;
+}
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 6317fa7c8d1..32a36da56fe 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -14,7 +14,11 @@ class Admin::GroupsController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def show
- @group = Group.with_statistics.joins(:route).group('routes.path').find_by_full_path(params[:id])
+ # Group.with_statistics doesn't behave nicely when including other relations.
+ # Group.find_by_full_path includes the routes relation to avoid a common N+1
+ # (at the expense of this action: there are two queries here to find and retrieve
+ # the Group with statistics).
+ @group = Group.with_statistics.find(group&.id)
@members = present_members(
@group.members.order("access_level DESC").page(params[:members_page]))
@requesters = present_members(
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 1773ac2d508..b735f9ff3b8 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -40,11 +40,11 @@ class IssuableFinder
requires_cross_project_access unless: -> { project? }
# This is used as a common filter for None / Any
- FILTER_NONE = 'none'.freeze
- FILTER_ANY = 'any'.freeze
+ FILTER_NONE = 'none'
+ FILTER_ANY = 'any'
# This is used in unassigning users
- NONE = '0'.freeze
+ NONE = '0'
attr_accessor :current_user, :params
diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb
index d001e18fea9..ed6d20b9585 100644
--- a/app/finders/todos_finder.rb
+++ b/app/finders/todos_finder.rb
@@ -21,7 +21,7 @@ class TodosFinder
requires_cross_project_access unless: -> { project? }
- NONE = '0'.freeze
+ NONE = '0'
TODO_TYPES = Set.new(%w(Issue MergeRequest Epic)).freeze
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index d3a5dae2188..cf9f74a63d8 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -18,8 +18,6 @@ module Mutations
required: true,
description: copy_field_description(Types::Notes::NoteType, :body)
- private
-
def resolve(args)
noteable = authorized_find!(id: args[:noteable_id])
@@ -37,6 +35,8 @@ module Mutations
}
end
+ private
+
def create_note_params(noteable, args)
{
noteable: noteable,
diff --git a/app/graphql/resolvers/full_path_resolver.rb b/app/graphql/resolvers/full_path_resolver.rb
index 972f318c806..2afd0411ea6 100644
--- a/app/graphql/resolvers/full_path_resolver.rb
+++ b/app/graphql/resolvers/full_path_resolver.rb
@@ -11,7 +11,7 @@ module Resolvers
end
def model_by_full_path(model, full_path)
- BatchLoader.for(full_path).batch(key: model) do |full_paths, loader, args|
+ BatchLoader::GraphQL.for(full_path).batch(key: model) do |full_paths, loader, args|
# `with_route` avoids an N+1 calculating full_path
args[:key].where_full_path_in(full_paths).with_route.each do |model_instance|
loader.call(model_instance.full_path, model_instance)
diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb
index 6988b451ec3..dd104e83f43 100644
--- a/app/graphql/resolvers/issues_resolver.rb
+++ b/app/graphql/resolvers/issues_resolver.rb
@@ -41,13 +41,11 @@ module Resolvers
type Types::IssueType, null: true
- alias_method :project, :object
-
def resolve(**args)
# The project could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` of the project to query for issues, so
# make sure it's loaded and not `nil` before continuing.
- project.sync if project.respond_to?(:sync)
+ project = object.respond_to?(:sync) ? object.sync : object
return Issue.none if project.nil?
# Will need to be be made group & namespace aware with
diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb
index b84e60066e1..1740d614b69 100644
--- a/app/graphql/resolvers/merge_requests_resolver.rb
+++ b/app/graphql/resolvers/merge_requests_resolver.rb
@@ -25,8 +25,10 @@ module Resolvers
# rubocop: disable CodeReuse/ActiveRecord
def batch_load(iid)
- BatchLoader.for(iid.to_s).batch(key: project) do |iids, loader, args|
- args[:key].merge_requests.where(iid: iids).each do |mr|
+ BatchLoader::GraphQL.for(iid.to_s).batch(key: project) do |iids, loader, args|
+ arg_key = args[:key].respond_to?(:sync) ? args[:key].sync : args[:key]
+
+ arg_key.merge_requests.where(iid: iids).each do |mr|
loader.call(mr.iid.to_s, mr)
end
end
diff --git a/app/graphql/resolvers/namespace_projects_resolver.rb b/app/graphql/resolvers/namespace_projects_resolver.rb
index 677ea808aeb..f5b60f91be6 100644
--- a/app/graphql/resolvers/namespace_projects_resolver.rb
+++ b/app/graphql/resolvers/namespace_projects_resolver.rb
@@ -9,13 +9,11 @@ module Resolvers
type Types::ProjectType, null: true
- alias_method :namespace, :object
-
def resolve(include_subgroups:)
# The namespace could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` or the `full_path` of the namespace
# to query for projects, so make sure it's loaded and not `nil` before continuing.
- namespace.sync if namespace.respond_to?(:sync)
+ namespace = object.respond_to?(:sync) ? object.sync : object
return Project.none if namespace.nil?
if include_subgroups
diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb
index bbe05f40999..8ef3ed9e8a5 100644
--- a/app/helpers/boards_helper.rb
+++ b/app/helpers/boards_helper.rb
@@ -10,7 +10,7 @@ module BoardsHelper
boards_endpoint: @boards_endpoint,
lists_endpoint: board_lists_path(board),
board_id: board.id,
- disabled: "#{!can?(current_user, :admin_list, current_board_parent)}",
+ disabled: (!can?(current_user, :create_non_backlog_issues, board)).to_s,
issue_link_base: build_issue_link_base,
root_path: root_path,
bulk_update_path: @bulk_issues_path,
diff --git a/app/helpers/jobs_helper.rb b/app/helpers/jobs_helper.rb
new file mode 100644
index 00000000000..46edba261dd
--- /dev/null
+++ b/app/helpers/jobs_helper.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module JobsHelper
+ def jobs_data
+ {
+ "endpoint" => project_job_path(@project, @build, format: :json),
+ "project_path" => @project.full_path,
+ "deployment_help_url" => help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting-failed-deployment-jobs'),
+ "runner_help_url" => help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'),
+ "runner_settings_url" => project_runners_path(@build.project, anchor: 'js-runners-settings'),
+ "variables_settings_url" => project_variables_path(@build.project, anchor: 'js-cicd-variables-settings'),
+ "page_path" => project_job_path(@project, @build),
+ "build_status" => @build.status,
+ "build_stage" => @build.stage,
+ "log_state" => '',
+ "build_options" => javascript_build_options
+ }
+ end
+end
diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb
index 04db1980b99..8b93ead0ee6 100644
--- a/app/mailers/emails/notes.rb
+++ b/app/mailers/emails/notes.rb
@@ -2,44 +2,44 @@
module Emails
module Notes
- def note_commit_email(recipient_id, note_id)
+ def note_commit_email(recipient_id, note_id, reason = nil)
setup_note_mail(note_id, recipient_id)
@commit = @note.noteable
@target_url = project_commit_url(*note_target_url_options)
- mail_answer_note_thread(@commit, @note, note_thread_options(recipient_id))
+ mail_answer_note_thread(@commit, @note, note_thread_options(recipient_id, reason))
end
- def note_issue_email(recipient_id, note_id)
+ def note_issue_email(recipient_id, note_id, reason = nil)
setup_note_mail(note_id, recipient_id)
@issue = @note.noteable
@target_url = project_issue_url(*note_target_url_options)
- mail_answer_note_thread(@issue, @note, note_thread_options(recipient_id))
+ mail_answer_note_thread(@issue, @note, note_thread_options(recipient_id, reason))
end
- def note_merge_request_email(recipient_id, note_id)
+ def note_merge_request_email(recipient_id, note_id, reason = nil)
setup_note_mail(note_id, recipient_id)
@merge_request = @note.noteable
@target_url = project_merge_request_url(*note_target_url_options)
- mail_answer_note_thread(@merge_request, @note, note_thread_options(recipient_id))
+ mail_answer_note_thread(@merge_request, @note, note_thread_options(recipient_id, reason))
end
- def note_project_snippet_email(recipient_id, note_id)
+ def note_project_snippet_email(recipient_id, note_id, reason = nil)
setup_note_mail(note_id, recipient_id)
@snippet = @note.noteable
@target_url = project_snippet_url(*note_target_url_options)
- mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id))
+ mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id, reason))
end
- def note_personal_snippet_email(recipient_id, note_id)
+ def note_personal_snippet_email(recipient_id, note_id, reason = nil)
setup_note_mail(note_id, recipient_id)
@snippet = @note.noteable
@target_url = snippet_url(@note.noteable)
- mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id))
+ mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id, reason))
end
private
@@ -48,11 +48,12 @@ module Emails
[@project || @group, @note.noteable, anchor: "note_#{@note.id}"]
end
- def note_thread_options(recipient_id)
+ def note_thread_options(recipient_id, reason)
{
from: sender(@note.author_id),
to: recipient(recipient_id, @project&.group || @group),
- subject: subject("#{@note.noteable.title} (#{@note.noteable.reference_link_text})")
+ subject: subject("#{@note.noteable.title} (#{@note.noteable.reference_link_text})"),
+ 'X-GitLab-NotificationReason' => reason
}
end
diff --git a/app/models/board.rb b/app/models/board.rb
index 50b6ca9b70f..b5d07f1b282 100644
--- a/app/models/board.rb
+++ b/app/models/board.rb
@@ -19,6 +19,7 @@ class Board < ApplicationRecord
def parent
@parent ||= group || project
end
+ alias_method :resource_parent, :parent
def group_board?
group_id.present?
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 64e372878e6..2b6f10ef79f 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -460,8 +460,8 @@ module Ci
canceled? && auto_canceled_by_id?
end
- def cancel_running
- retry_optimistic_lock(cancelable_statuses) do |cancelable|
+ def cancel_running(retries: nil)
+ retry_optimistic_lock(cancelable_statuses, retries) do |cancelable|
cancelable.find_each do |job|
yield(job) if block_given?
job.cancel
@@ -469,10 +469,10 @@ module Ci
end
end
- def auto_cancel_running(pipeline)
+ def auto_cancel_running(pipeline, retries: nil)
update(auto_canceled_by: pipeline)
- cancel_running do |job|
+ cancel_running(retries: retries) do |job|
job.auto_canceled_by = pipeline
end
end
@@ -670,6 +670,7 @@ module Ci
variables.append(key: 'CI_COMMIT_REF_PROTECTED', value: (!!protected_ref?).to_s)
if merge_request_event? && merge_request
+ variables.append(key: 'CI_MERGE_REQUEST_EVENT_TYPE', value: merge_request_event_type.to_s)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', value: source_sha.to_s)
variables.append(key: 'CI_MERGE_REQUEST_TARGET_BRANCH_SHA', value: target_sha.to_s)
variables.concat(merge_request.predefined_variables)
@@ -772,10 +773,18 @@ module Ci
triggered_by_merge_request? && target_sha.present?
end
+ def merge_train_pipeline?
+ merge_request_pipeline? && merge_train_ref?
+ end
+
def merge_request_ref?
MergeRequest.merge_request_ref?(ref)
end
+ def merge_train_ref?
+ MergeRequest.merge_train_ref?(ref)
+ end
+
def matches_sha_or_source_sha?(sha)
self.sha == sha || self.source_sha == sha
end
@@ -804,6 +813,20 @@ module Ci
errors ? errors.full_messages.to_sentence : ""
end
+ def merge_request_event_type
+ return unless merge_request_event?
+
+ strong_memoize(:merge_request_event_type) do
+ if detached_merge_request_pipeline?
+ :detached
+ elsif merge_request_pipeline?
+ :merged_result
+ elsif merge_train_pipeline?
+ :merge_train
+ end
+ end
+ end
+
private
def ci_yaml_from_repo
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index eefe9f00836..a998d9b7e1b 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -277,6 +277,10 @@ module Issuable
end
end
+ def resource_parent
+ project
+ end
+
def milestone_available?
project_id == milestone&.project_id || project.ancestors_upto.compact.include?(milestone&.group)
end
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index 3a486632800..8b011bca72c 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -33,12 +33,12 @@ module Routable
#
# Returns a single object, or nil.
def find_by_full_path(path, follow_redirects: false)
- increment_counter(:routable_find_by_full_path, 'Number of calls to Routable.find_by_full_path')
+ routable_calls_counter.increment(method: 'find_by_full_path')
if Feature.enabled?(:routable_two_step_lookup)
# Case sensitive match first (it's cheaper and the usual case)
# If we didn't have an exact match, we perform a case insensitive search
- found = joins(:route).find_by(routes: { path: path }) || where_full_path_in([path]).take
+ found = includes(:route).find_by(routes: { path: path }) || where_full_path_in([path]).take
else
order_sql = Arel.sql("(CASE WHEN routes.path = #{connection.quote(path)} THEN 0 ELSE 1 END)")
found = where_full_path_in([path]).reorder(order_sql).take
@@ -61,22 +61,18 @@ module Routable
def where_full_path_in(paths)
return none if paths.empty?
- increment_counter(:routable_where_full_path_in, 'Number of calls to Routable.where_full_path_in')
+ routable_calls_counter.increment(method: 'where_full_path_in')
wheres = paths.map do |path|
"(LOWER(routes.path) = LOWER(#{connection.quote(path)}))"
end
- joins(:route).where(wheres.join(' OR '))
+ includes(:route).where(wheres.join(' OR ')).references(:routes)
end
# Temporary instrumentation of method calls
- def increment_counter(counter, description)
- @counters[counter] ||= Gitlab::Metrics.counter(counter, description)
-
- @counters[counter].increment
- rescue
- # ignore the error
+ def routable_calls_counter
+ @routable_calls_counter ||= Gitlab::Metrics.counter(:gitlab_routable_calls_total, 'Number of calls to Routable by method')
end
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 392d7368033..52d54be39a9 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -51,6 +51,7 @@ class Event < ApplicationRecord
belongs_to :author, class_name: "User"
belongs_to :project
+ belongs_to :group
belongs_to :target, -> {
# If the association for "target" defines an "author" association we want to
diff --git a/app/models/member.rb b/app/models/member.rb
index dbae1076670..6457fe9ef0c 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -399,7 +399,7 @@ class Member < ApplicationRecord
end
def post_update_hook
- # override in sub class
+ system_hook_service.execute_hooks_for(self, :update)
end
def post_destroy_hook
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index bfd636fa62a..28e450f9b30 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1142,6 +1142,10 @@ class MergeRequest < ApplicationRecord
ref.start_with?("refs/#{Repository::REF_MERGE_REQUEST}/")
end
+ def self.merge_train_ref?(ref)
+ %r{\Arefs/#{Repository::REF_MERGE_REQUEST}/\d+/train\z}.match?(ref)
+ end
+
def in_locked_state
begin
lock_mr
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 2402fa8e38f..4db2b7a74e5 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -197,7 +197,7 @@ class MergeRequestDiff < ApplicationRecord
def lines_count
strong_memoize(:lines_count) do
- diffs.diff_files.sum(&:line_count)
+ raw_diffs(limits: false).line_count
end
end
@@ -222,6 +222,10 @@ class MergeRequestDiff < ApplicationRecord
commits.last
end
+ def last_commit
+ commits.first
+ end
+
def base_commit
return unless base_commit_sha
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 2ad2838111e..915978d37b8 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -16,6 +16,7 @@ class Milestone < ApplicationRecord
include Referable
include StripAttribute
include Milestoneish
+ include FromUnion
include Gitlab::SQL::Pattern
cache_markdown_field :title, pipeline: :single_line
@@ -24,6 +25,12 @@ class Milestone < ApplicationRecord
belongs_to :project
belongs_to :group
+ # A one-to-one relationship is set up here as part of a MVC: https://gitlab.com/gitlab-org/gitlab-ce/issues/62402
+ # However, on the long term, we will want a many-to-many relationship between Release and Milestone.
+ # The "has_one through" allows us today to set up this one-to-one relationship while setting up the architecture for the long-term (ie intermediate table).
+ has_one :milestone_release
+ has_one :release, through: :milestone_release
+
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.milestones&.maximum(:iid) }
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.milestones&.maximum(:iid) }
@@ -59,6 +66,7 @@ class Milestone < ApplicationRecord
validate :milestone_type_check
validate :start_date_should_be_less_than_due_date, if: proc { |m| m.start_date.present? && m.due_date.present? }
validate :dates_within_4_digits
+ validates_associated :milestone_release, message: -> (_, obj) { obj[:value].errors.full_messages.join(",") }
strip_attributes :title
@@ -253,6 +261,7 @@ class Milestone < ApplicationRecord
def parent
group || project
end
+ alias_method :resource_parent, :parent
def group_milestone?
group_id.present?
diff --git a/app/models/milestone_release.rb b/app/models/milestone_release.rb
new file mode 100644
index 00000000000..c8743a8cad8
--- /dev/null
+++ b/app/models/milestone_release.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class MilestoneRelease < ApplicationRecord
+ belongs_to :milestone
+ belongs_to :release
+
+ validates :milestone_id, uniqueness: { scope: [:release_id] }
+ validate :same_project_between_milestone_and_release
+
+ private
+
+ def same_project_between_milestone_and_release
+ return if milestone&.project_id == release&.project_id
+
+ errors.add(:base, 'does not have the same project as the milestone')
+ end
+end
diff --git a/app/models/note.rb b/app/models/note.rb
index ebd13675dc9..0d024b0a25c 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -477,6 +477,7 @@ class Note < ApplicationRecord
def parent
project
end
+ alias_method :resource_parent, :parent
private
diff --git a/app/models/release.rb b/app/models/release.rb
index 459a7c29ad0..b2e65974aa0 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -12,6 +12,12 @@ class Release < ApplicationRecord
has_many :links, class_name: 'Releases::Link'
+ # A one-to-one relationship is set up here as part of a MVC: https://gitlab.com/gitlab-org/gitlab-ce/issues/62402
+ # However, on the long term, we will want a many-to-many relationship between Release and Milestone.
+ # The "has_one through" allows us today to set up this one-to-one relationship while setting up the architecture for the long-term (ie intermediate table).
+ has_one :milestone_release
+ has_one :milestone, through: :milestone_release
+
default_value_for :released_at, allows_nil: false do
Time.zone.now
end
@@ -20,6 +26,7 @@ class Release < ApplicationRecord
validates :description, :project, :tag, presence: true
validates :name, presence: true, on: :create
+ validates_associated :milestone_release, message: -> (_, obj) { obj[:value].errors.full_messages.join(",") }
scope :sorted, -> { order(released_at: :desc) }
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 7882b2b3036..5cb4b56a114 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -456,6 +456,10 @@ class Repository
def after_import
expire_content_cache
+ # This call is stubbed in tests due to being an expensive operation
+ # It can be reenabled for specific tests via:
+ #
+ # allow(DetectRepositoryLanguagesWorker).to receive(:perform_async).and_call_original
DetectRepositoryLanguagesWorker.perform_async(project.id)
end
diff --git a/app/models/service.rb b/app/models/service.rb
index f6d8fb1fb46..431c5881460 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -174,7 +174,7 @@ class Service < ApplicationRecord
# Also keep track of updated properties in a similar way as ActiveModel::Dirty
def self.prop_accessor(*args)
args.each do |arg|
- class_eval %{
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
unless method_defined?(arg)
def #{arg}
properties['#{arg}']
@@ -198,7 +198,7 @@ class Service < ApplicationRecord
def #{arg}_was
updated_properties['#{arg}']
end
- }
+ RUBY
end
end
@@ -209,12 +209,12 @@ class Service < ApplicationRecord
self.prop_accessor(*args)
args.each do |arg|
- class_eval %{
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
def #{arg}?
# '!!' is used because nil or empty string is converted to nil
!!ActiveRecord::Type::Boolean.new.cast(#{arg})
end
- }
+ RUBY
end
end
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 1ec04189482..f7f30aed832 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -146,6 +146,7 @@ class Todo < ApplicationRecord
def parent
project
end
+ alias_method :resource_parent, :parent
def unmergeable?
action == UNMERGEABLE
diff --git a/app/policies/board_policy.rb b/app/policies/board_policy.rb
index 4bf1e7bd3e1..b8435dad3f1 100644
--- a/app/policies/board_policy.rb
+++ b/app/policies/board_policy.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class BoardPolicy < BasePolicy
+ include FindGroupProjects
+
delegate { @subject.parent }
condition(:is_group_board) { @subject.group_board? }
@@ -13,4 +15,20 @@ class BoardPolicy < BasePolicy
enable :read_milestone
enable :read_issue
end
+
+ condition(:reporter_of_group_projects) do
+ next unless @user
+
+ group_projects_for(user: @user, group: @subject.parent)
+ .visible_to_user_and_access_level(@user, ::Gitlab::Access::REPORTER)
+ .exists?
+ end
+
+ rule { is_group_board & reporter_of_group_projects }.policy do
+ enable :create_non_backlog_issues
+ end
+
+ rule { is_project_board & can?(:admin_issue) }.policy do
+ enable :create_non_backlog_issues
+ end
end
diff --git a/app/policies/concerns/find_group_projects.rb b/app/policies/concerns/find_group_projects.rb
new file mode 100644
index 00000000000..e2cb90079c7
--- /dev/null
+++ b/app/policies/concerns/find_group_projects.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module FindGroupProjects
+ extend ActiveSupport::Concern
+
+ def group_projects_for(user:, group:)
+ GroupProjectsFinder.new(
+ group: group,
+ current_user: user,
+ options: { include_subgroups: true, only_owned: true }
+ ).execute
+ end
+end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 5d2b74b17a2..c726c7c24a7 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class GroupPolicy < BasePolicy
+ include FindGroupProjects
+
desc "Group is public"
with_options scope: :subject, score: 0
condition(:public_group) { @subject.public? }
@@ -22,7 +24,7 @@ class GroupPolicy < BasePolicy
condition(:can_change_parent_share_with_group_lock) { can?(:change_share_with_group_lock, @subject.parent) }
condition(:has_projects) do
- GroupProjectsFinder.new(group: @subject, current_user: @user, options: { include_subgroups: true, only_owned: true }).execute.any?
+ group_projects_for(user: @user, group: @subject).any?
end
with_options scope: :subject, score: 0
diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb
index b928988ed8c..5231a8efa55 100644
--- a/app/presenters/ci/build_runner_presenter.rb
+++ b/app/presenters/ci/build_runner_presenter.rb
@@ -4,8 +4,8 @@ module Ci
class BuildRunnerPresenter < SimpleDelegator
include Gitlab::Utils::StrongMemoize
- RUNNER_REMOTE_TAG_PREFIX = 'refs/tags/'.freeze
- RUNNER_REMOTE_BRANCH_PREFIX = 'refs/remotes/origin/'.freeze
+ RUNNER_REMOTE_TAG_PREFIX = 'refs/tags/'
+ RUNNER_REMOTE_BRANCH_PREFIX = 'refs/remotes/origin/'
def artifacts
return unless options[:artifacts]
diff --git a/app/presenters/ci/pipeline_presenter.rb b/app/presenters/ci/pipeline_presenter.rb
index 358473d0a74..a96f97988b2 100644
--- a/app/presenters/ci/pipeline_presenter.rb
+++ b/app/presenters/ci/pipeline_presenter.rb
@@ -34,6 +34,18 @@ module Ci
end
end
+ NAMES = {
+ merge_train: s_('Pipeline|Merge train pipeline'),
+ merged_result: s_('Pipeline|Merged result pipeline'),
+ detached: s_('Pipeline|Detached merge request pipeline')
+ }.freeze
+
+ def name
+ # Currently, `merge_request_event_type` is the only source to name pipelines
+ # but this could be extended with the other types in the future.
+ NAMES.fetch(pipeline.merge_request_event_type, s_('Pipeline|Pipeline'))
+ end
+
def ref_text
if pipeline.detached_merge_request_pipeline?
_("for %{link_to_merge_request} with %{link_to_merge_request_source_branch}").html_safe % { link_to_merge_request: link_to_merge_request, link_to_merge_request_source_branch: link_to_merge_request_source_branch }
diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb
index fff6d23efdf..d1bf0344b66 100644
--- a/app/presenters/clusterable_presenter.rb
+++ b/app/presenters/clusterable_presenter.rb
@@ -53,6 +53,11 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
raise NotImplementedError
end
+ # Will be overidden in EE
+ def environments_cluster_path(cluster)
+ nil
+ end
+
def empty_state_help_text
nil
end
diff --git a/app/serializers/entity_date_helper.rb b/app/serializers/entity_date_helper.rb
index f515abe5917..d8f267d7183 100644
--- a/app/serializers/entity_date_helper.rb
+++ b/app/serializers/entity_date_helper.rb
@@ -46,12 +46,14 @@ module EntityDateHelper
# If start date is provided and elapsed, with no due date, it returns "# days elapsed"
def remaining_days_in_words(due_date, start_date = nil)
if due_date&.past?
- content_tag(:strong, 'Past due')
+ content_tag(:strong, _('Past due'))
+ elsif due_date&.today?
+ content_tag(:strong, _('Today'))
elsif start_date&.future?
- content_tag(:strong, 'Upcoming')
+ content_tag(:strong, _('Upcoming'))
elsif due_date
is_upcoming = (due_date - Date.today).to_i > 0
- time_ago = time_ago_in_words(due_date)
+ time_ago = distance_of_time_in_words(due_date, Date.today)
# https://gitlab.com/gitlab-org/gitlab-ce/issues/49440
#
@@ -59,8 +61,8 @@ module EntityDateHelper
# of the string instead of piecewise translations.
content = time_ago
.gsub(/\d+/) { |match| "<strong>#{match}</strong>" }
- .remove("about ")
- remaining_or_ago = is_upcoming ? _("remaining") : _("ago")
+ .remove('about ')
+ remaining_or_ago = is_upcoming ? _('remaining') : _('ago')
"#{content} #{remaining_or_ago}".html_safe
elsif start_date&.past?
diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb
index 9ef93b2387f..94e8b174f0f 100644
--- a/app/serializers/pipeline_entity.rb
+++ b/app/serializers/pipeline_entity.rb
@@ -2,6 +2,9 @@
class PipelineEntity < Grape::Entity
include RequestAwareEntity
+ include Gitlab::Utils::StrongMemoize
+
+ delegate :name, :failure_reason, to: :presented_pipeline
expose :id
expose :user, using: UserEntity
@@ -36,6 +39,7 @@ class PipelineEntity < Grape::Entity
expose :ordered_stages, as: :stages, using: StageEntity
expose :duration
expose :finished_at
+ expose :name
end
expose :merge_request, if: -> (*) { has_presentable_merge_request? }, with: MergeRequestForPipelineEntity do |pipeline|
@@ -59,13 +63,11 @@ class PipelineEntity < Grape::Entity
end
expose :commit, using: CommitEntity
+ expose :merge_request_event_type, if: -> (pipeline, _) { pipeline.merge_request_event? }
expose :source_sha, if: -> (pipeline, _) { pipeline.merge_request_pipeline? }
expose :target_sha, if: -> (pipeline, _) { pipeline.merge_request_pipeline? }
expose :yaml_errors, if: -> (pipeline, _) { pipeline.has_yaml_errors? }
-
- expose :failure_reason, if: -> (pipeline, _) { pipeline.failure_reason? } do |pipeline|
- pipeline.present.failure_reason
- end
+ expose :failure_reason, if: -> (pipeline, _) { pipeline.failure_reason? }
expose :retry_path, if: -> (*) { can_retry? } do |pipeline|
retry_project_pipeline_path(pipeline.project, pipeline)
@@ -97,4 +99,10 @@ class PipelineEntity < Grape::Entity
def detailed_status
pipeline.detailed_status(request.current_user)
end
+
+ def presented_pipeline
+ strong_memoize(:presented_pipeline) do
+ pipeline.present
+ end
+ end
end
diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb
index 73f3408a240..22ade0b0658 100644
--- a/app/services/audit_event_service.rb
+++ b/app/services/audit_event_service.rb
@@ -21,6 +21,10 @@ class AuditEventService
log_security_event_to_database
end
+ def log_security_event_to_file
+ file_logger.info(base_payload.merge(formatted_details))
+ end
+
private
def base_payload
@@ -39,10 +43,6 @@ class AuditEventService
@details.merge(@details.slice(:from, :to).transform_values(&:to_s))
end
- def log_security_event_to_file
- file_logger.info(base_payload.merge(formatted_details))
- end
-
def log_security_event_to_database
SecurityEvent.create(base_payload.merge(details: @details))
end
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb
index 0a069320936..9c210f3a1f5 100644
--- a/app/services/auth/container_registry_authentication_service.rb
+++ b/app/services/auth/container_registry_authentication_service.rb
@@ -2,7 +2,7 @@
module Auth
class ContainerRegistryAuthenticationService < BaseService
- AUDIENCE = 'container_registry'.freeze
+ AUDIENCE = 'container_registry'
def execute(authentication_abilities:)
@authentication_abilities = authentication_abilities
@@ -124,13 +124,21 @@ module Auth
build_can_pull?(requested_project) || user_can_pull?(requested_project) || deploy_token_can_pull?(requested_project)
when 'push'
build_can_push?(requested_project) || user_can_push?(requested_project)
- when '*', 'delete'
+ when 'delete'
+ build_can_delete?(requested_project) || user_can_admin?(requested_project)
+ when '*'
user_can_admin?(requested_project)
else
false
end
end
+ def build_can_delete?(requested_project)
+ # Build can delete only from the project from which it originates
+ has_authentication_ability?(:build_destroy_container_image) &&
+ requested_project == project
+ end
+
def registry
Gitlab.config.registry
end
diff --git a/app/services/auto_merge_service.rb b/app/services/auto_merge_service.rb
index 95bf2db2018..053c6d71fbb 100644
--- a/app/services/auto_merge_service.rb
+++ b/app/services/auto_merge_service.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class AutoMergeService < BaseService
- STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS = 'merge_when_pipeline_succeeds'.freeze
+ STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS = 'merge_when_pipeline_succeeds'
STRATEGIES = [STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS].freeze
class << self
diff --git a/app/services/clusters/applications/check_installation_progress_service.rb b/app/services/clusters/applications/check_installation_progress_service.rb
index 65d08966802..1ce6e0c1cb0 100644
--- a/app/services/clusters/applications/check_installation_progress_service.rb
+++ b/app/services/clusters/applications/check_installation_progress_service.rb
@@ -33,6 +33,10 @@ module Clusters
def timed_out?
Time.now.utc - app.updated_at.utc > ClusterWaitForAppInstallationWorker::TIMEOUT
end
+
+ def remove_installation_pod
+ helm_api.delete_pod!(pod_name)
+ end
end
end
end
diff --git a/app/services/clusters/applications/check_uninstall_progress_service.rb b/app/services/clusters/applications/check_uninstall_progress_service.rb
index 6a618d61c4f..fe9c488bdfd 100644
--- a/app/services/clusters/applications/check_uninstall_progress_service.rb
+++ b/app/services/clusters/applications/check_uninstall_progress_service.rb
@@ -15,7 +15,7 @@ module Clusters
rescue StandardError => e
app.make_errored!(_('Application uninstalled but failed to destroy: %{error_message}') % { error_message: e.message })
ensure
- remove_installation_pod
+ remove_uninstallation_pod
end
def check_timeout
@@ -33,6 +33,10 @@ module Clusters
def timed_out?
Time.now.utc - app.updated_at.utc > WaitForUninstallAppWorker::TIMEOUT
end
+
+ def remove_uninstallation_pod
+ helm_api.delete_pod!(pod_name)
+ end
end
end
end
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index e7464fd9d5f..39266a6c961 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -95,16 +95,23 @@ class EventCreateService
private
def create_record_event(record, current_user, status)
- create_event(record.project, current_user, status, target_id: record.id, target_type: record.class.name)
+ create_event(record.resource_parent, current_user, status, target_id: record.id, target_type: record.class.name)
end
- def create_event(project, current_user, status, attributes = {})
+ def create_event(resource_parent, current_user, status, attributes = {})
attributes.reverse_merge!(
- project: project,
action: status,
author_id: current_user.id
)
+ resource_parent_attr = case resource_parent
+ when Project
+ :project
+ when Group
+ :group
+ end
+ attributes[resource_parent_attr] = resource_parent if resource_parent_attr
+
Event.create!(attributes)
end
end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 2ab6e88599f..3555864f834 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -221,6 +221,7 @@ class IssuableBaseService < BaseService
# We have to perform this check before saving the issuable as Rails resets
# the changed fields upon calling #save.
update_project_counters = issuable.project && update_project_counter_caches?(issuable)
+ ensure_milestone_available(issuable)
if issuable.with_transaction_returning_status { issuable.save(touch: should_touch) }
# We do not touch as it will affect a update on updated_at field
diff --git a/app/services/merge_requests/rebase_service.rb b/app/services/merge_requests/rebase_service.rb
index 27c16ba1777..4d36dd4feae 100644
--- a/app/services/merge_requests/rebase_service.rb
+++ b/app/services/merge_requests/rebase_service.rb
@@ -2,7 +2,7 @@
module MergeRequests
class RebaseService < MergeRequests::WorkingCopyBaseService
- REBASE_ERROR = 'Rebase failed. Please rebase locally'.freeze
+ REBASE_ERROR = 'Rebase failed. Please rebase locally'
def execute(merge_request)
@merge_request = merge_request
diff --git a/app/services/milestones/find_or_create_service.rb b/app/services/milestones/find_or_create_service.rb
new file mode 100644
index 00000000000..881011e5106
--- /dev/null
+++ b/app/services/milestones/find_or_create_service.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Milestones
+ class FindOrCreateService
+ attr_accessor :project, :current_user, :params
+
+ def initialize(project, user, params = {})
+ @project, @current_user, @params = project, user, params.dup
+ end
+
+ def execute
+ find_milestone || create_milestone
+ end
+
+ private
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def find_milestone
+ groups = project.group&.self_and_ancestors_ids
+ Milestone.for_projects_and_groups([project.id], groups).find_by(title: params["title"])
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def create_milestone
+ return unless current_user.can?(:admin_milestone, project)
+
+ new_milestone if new_milestone.persisted?
+ end
+
+ def new_milestone
+ @new_milestone ||= CreateService.new(project, current_user, params).execute
+ end
+ end
+end
diff --git a/app/services/milestones/transfer_service.rb b/app/services/milestones/transfer_service.rb
new file mode 100644
index 00000000000..1efbfed4853
--- /dev/null
+++ b/app/services/milestones/transfer_service.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+# Milestones::TransferService class
+#
+# Used for recreating the missing group milestones at project level when
+# transferring a project to a new namespace
+#
+module Milestones
+ class TransferService
+ attr_reader :current_user, :old_group, :project
+
+ def initialize(current_user, old_group, project)
+ @current_user = current_user
+ @old_group = old_group
+ @project = project
+ end
+
+ def execute
+ return unless old_group.present?
+
+ Milestone.transaction do
+ milestones_to_transfer.find_each do |milestone|
+ new_milestone = find_or_create_milestone(milestone)
+
+ update_issues_milestone(milestone.id, new_milestone&.id)
+ update_merge_requests_milestone(milestone.id, new_milestone&.id)
+ end
+ end
+ end
+
+ private
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def milestones_to_transfer
+ Milestone.from_union([
+ group_milestones_applied_to_issues,
+ group_milestones_applied_to_merge_requests
+ ])
+ .reorder(nil)
+ .distinct
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def group_milestones_applied_to_issues
+ Milestone.joins(:issues)
+ .where(
+ issues: { project_id: project.id },
+ group_id: old_group.id
+ )
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def group_milestones_applied_to_merge_requests
+ Milestone.joins(:merge_requests)
+ .where(
+ merge_requests: { target_project_id: project.id },
+ group_id: old_group.id
+ )
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def find_or_create_milestone(milestone)
+ params = milestone.attributes.slice('title', 'description', 'start_date', 'due_date')
+
+ FindOrCreateService.new(project, current_user, params).execute
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def update_issues_milestone(old_milestone_id, new_milestone_id)
+ Issue.where(project: project, milestone_id: old_milestone_id)
+ .update_all(milestone_id: new_milestone_id)
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def update_merge_requests_milestone(old_milestone_id, new_milestone_id)
+ MergeRequest.where(project: project, milestone_id: old_milestone_id)
+ .update_all(milestone_id: new_milestone_id)
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 5b8c1288854..a4243b7bc5e 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -285,7 +285,7 @@ class NotificationService
recipients = NotificationRecipientService.build_new_note_recipients(note)
recipients.each do |recipient|
- mailer.send(notify_method, recipient.user.id, note.id).deliver_later
+ mailer.send(notify_method, recipient.user.id, note.id, recipient.reason).deliver_later
end
end
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 5893b8eedff..108c4a79cde 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -6,7 +6,7 @@ module Projects
DestroyError = Class.new(StandardError)
- DELETED_FLAG = '+deleted'.freeze
+ DELETED_FLAG = '+deleted'
REPO_REMOVAL_DELAY = 5.minutes.to_i
def async_execute
diff --git a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
index 9b72480d18b..5ef7e03ea02 100644
--- a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
@@ -5,7 +5,7 @@
module Projects
module LfsPointers
class LfsDownloadLinkListService < BaseService
- DOWNLOAD_ACTION = 'download'.freeze
+ DOWNLOAD_ACTION = 'download'
DownloadLinksError = Class.new(StandardError)
DownloadLinkNotFound = Class.new(StandardError)
diff --git a/app/services/projects/lfs_pointers/lfs_list_service.rb b/app/services/projects/lfs_pointers/lfs_list_service.rb
index 22160017f4f..a07fa93a279 100644
--- a/app/services/projects/lfs_pointers/lfs_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_list_service.rb
@@ -4,7 +4,7 @@
module Projects
module LfsPointers
class LfsListService < BaseService
- REV = 'HEAD'.freeze
+ REV = 'HEAD'
# Retrieve all lfs blob pointers and returns a hash
# with the structure { lfs_file_oid => lfs_file_size }
diff --git a/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb b/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
index 5ba0f50f2ff..4224b56c42c 100644
--- a/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
@@ -8,9 +8,9 @@ module Projects
class LfsObjectDownloadListService < BaseService
include Gitlab::Utils::StrongMemoize
- HEAD_REV = 'HEAD'.freeze
+ HEAD_REV = 'HEAD'
LFS_ENDPOINT_PATTERN = /^\t?url\s*=\s*(.+)$/.freeze
- LFS_BATCH_API_ENDPOINT = '/info/lfs/objects/batch'.freeze
+ LFS_BATCH_API_ENDPOINT = '/info/lfs/objects/batch'
LfsObjectDownloadListError = Class.new(StandardError)
diff --git a/app/services/projects/open_issues_count_service.rb b/app/services/projects/open_issues_count_service.rb
index ee9884e9042..bc8f7f342f7 100644
--- a/app/services/projects/open_issues_count_service.rb
+++ b/app/services/projects/open_issues_count_service.rb
@@ -7,8 +7,8 @@ module Projects
include Gitlab::Utils::StrongMemoize
# Cache keys used to store issues count
- PUBLIC_COUNT_KEY = 'public_open_issues_count'.freeze
- TOTAL_COUNT_KEY = 'total_open_issues_count'.freeze
+ PUBLIC_COUNT_KEY = 'public_open_issues_count'
+ TOTAL_COUNT_KEY = 'total_open_issues_count'
def initialize(project, user = nil)
@user = user
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 233dcf37e35..078a751025f 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -72,6 +72,9 @@ module Projects
# Move missing group labels to project
Labels::TransferService.new(current_user, @old_group, project).execute
+ # Move missing group milestones
+ Milestones::TransferService.new(current_user, @old_group, project).execute
+
# Move uploads
move_project_uploads(project)
diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb
index 5caeb4cfa5f..fa7a4f0ed82 100644
--- a/app/services/projects/update_pages_service.rb
+++ b/app/services/projects/update_pages_service.rb
@@ -7,11 +7,11 @@ module Projects
BLOCK_SIZE = 32.kilobytes
MAX_SIZE = 1.terabyte
- PUBLIC_DIR = 'public'.freeze
+ PUBLIC_DIR = 'public'
# this has to be invalid group name,
# as it shares the namespace with groups
- TMP_EXTRACT_PATH = '@pages.tmp'.freeze
+ TMP_EXTRACT_PATH = '@pages.tmp'
attr_reader :build
diff --git a/app/services/releases/concerns.rb b/app/services/releases/concerns.rb
index 618d96717b8..b5412e97284 100644
--- a/app/services/releases/concerns.rb
+++ b/app/services/releases/concerns.rb
@@ -47,6 +47,27 @@ module Releases
project.repository
end
end
+
+ def milestone
+ return unless params[:milestone]
+
+ strong_memoize(:milestone) do
+ MilestonesFinder.new(
+ project: project,
+ current_user: current_user,
+ project_ids: Array(project.id),
+ title: params[:milestone]
+ ).execute.first
+ end
+ end
+
+ def inexistent_milestone?
+ params[:milestone] && !params[:milestone].empty? && !milestone
+ end
+
+ def param_for_milestone_title_provided?
+ params[:milestone].present? || params[:milestone]&.empty?
+ end
end
end
end
diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb
index 5b13ac631ba..c91d43084d3 100644
--- a/app/services/releases/create_service.rb
+++ b/app/services/releases/create_service.rb
@@ -7,6 +7,7 @@ module Releases
def execute
return error('Access Denied', 403) unless allowed?
return error('Release already exists', 409) if release
+ return error('Milestone does not exist', 400) if inexistent_milestone?
tag = ensure_tag
@@ -59,7 +60,8 @@ module Releases
tag: tag.name,
sha: tag.dereferenced_target.sha,
released_at: released_at,
- links_attributes: params.dig(:assets, 'links') || []
+ links_attributes: params.dig(:assets, 'links') || [],
+ milestone: milestone
)
end
end
diff --git a/app/services/releases/update_service.rb b/app/services/releases/update_service.rb
index fabfa398c59..70acc68f747 100644
--- a/app/services/releases/update_service.rb
+++ b/app/services/releases/update_service.rb
@@ -9,6 +9,9 @@ module Releases
return error('Release does not exist', 404) unless release
return error('Access Denied', 403) unless allowed?
return error('params is empty', 400) if empty_params?
+ return error('Milestone does not exist', 400) if inexistent_milestone?
+
+ params[:milestone] = milestone if param_for_milestone_title_provided?
if release.update(params)
success(tag: existing_tag, release: release)
diff --git a/app/services/submit_usage_ping_service.rb b/app/services/submit_usage_ping_service.rb
index 4f10f220298..415a02ab337 100644
--- a/app/services/submit_usage_ping_service.rb
+++ b/app/services/submit_usage_ping_service.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class SubmitUsagePingService
- URL = 'https://version.gitlab.com/usage_data'.freeze
+ URL = 'https://version.gitlab.com/usage_data'
METRICS = %w[leader_issues instance_issues percentage_issues leader_notes instance_notes
percentage_notes leader_milestones instance_milestones percentage_milestones
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 858e04f43b2..34260d12a62 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -74,9 +74,11 @@ class SystemHooksService
when ProjectMember
return "user_add_to_team" if event == :create
return "user_remove_from_team" if event == :destroy
+ return "user_update_for_team" if event == :update
when GroupMember
return 'user_add_to_group' if event == :create
return 'user_remove_from_group' if event == :destroy
+ return 'user_update_for_group' if event == :update
else
"#{model.class.name.downcase}_#{event}"
end
diff --git a/app/services/wikis/create_attachment_service.rb b/app/services/wikis/create_attachment_service.rb
index df31ad7c8ea..6ef6cbc3c12 100644
--- a/app/services/wikis/create_attachment_service.rb
+++ b/app/services/wikis/create_attachment_service.rb
@@ -2,7 +2,7 @@
module Wikis
class CreateAttachmentService < Files::CreateService
- ATTACHMENT_PATH = 'uploads'.freeze
+ ATTACHMENT_PATH = 'uploads'
MAX_FILENAME_LENGTH = 255
delegate :wiki, to: :project
diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb
index 0a44d60778d..499807d1438 100644
--- a/app/uploaders/object_storage.rb
+++ b/app/uploaders/object_storage.rb
@@ -23,7 +23,7 @@ module ObjectStorage
end
end
- TMP_UPLOAD_PATH = 'tmp/uploads'.freeze
+ TMP_UPLOAD_PATH = 'tmp/uploads'
module Store
LOCAL = 1
diff --git a/app/validators/addressable_url_validator.rb b/app/validators/addressable_url_validator.rb
index bb445499cee..f292730441c 100644
--- a/app/validators/addressable_url_validator.rb
+++ b/app/validators/addressable_url_validator.rb
@@ -42,6 +42,11 @@
class AddressableUrlValidator < ActiveModel::EachValidator
attr_reader :record
+ # By default, we avoid checking the dns rebinding protection
+ # when saving/updating a record. Sometimes, the url
+ # is not resolvable at that point, and some automated
+ # tasks that uses that url won't work.
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/66723
BLOCKER_VALIDATE_OPTIONS = {
schemes: %w(http https),
ports: [],
@@ -49,7 +54,8 @@ class AddressableUrlValidator < ActiveModel::EachValidator
allow_local_network: true,
ascii_only: false,
enforce_user: false,
- enforce_sanitization: false
+ enforce_sanitization: false,
+ dns_rebind_protection: false
}.freeze
DEFAULT_OPTIONS = BLOCKER_VALIDATE_OPTIONS.merge({
diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml
index a0a00ac5d96..1001a69b787 100644
--- a/app/views/admin/background_jobs/show.html.haml
+++ b/app/views/admin/background_jobs/show.html.haml
@@ -1,10 +1,8 @@
-- @no_container = true
- page_title "Background Jobs"
-%div{ class: container_class }
- %h3.page-title Background Jobs
- %p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing
+%h3.page-title Background Jobs
+%p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing
- %hr
- .card
- %iframe{ src: sidekiq_path, width: '100%', height: 970, style: "border: 0" }
+%hr
+.card
+ %iframe{ src: sidekiq_path, width: '100%', height: 970, style: "border: 0" }
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index c29ecb43fe6..8aca61efe7b 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -1,167 +1,165 @@
-- @no_container = true
- breadcrumb_title "Dashboard"
-%div{ class: container_class }
- = render_if_exists 'admin/licenses/breakdown', license: @license
+= render_if_exists 'admin/licenses/breakdown', license: @license
- .admin-dashboard.prepend-top-default
- .row
- .col-sm-4
- .info-well.dark-well
- .well-segment.well-centered
- = link_to admin_projects_path do
- %h3.text-center
- Projects:
- = approximate_count_with_delimiters(@counts, Project)
- %hr
- = link_to('New project', new_project_path, class: "btn btn-success")
- .col-sm-4
- .info-well.dark-well
- .well-segment.well-centered
- = link_to admin_users_path do
- %h3.text-center
- Users:
- = approximate_count_with_delimiters(@counts, User)
- %hr
- .btn-group.d-flex{ role: 'group' }
- = link_to 'New user', new_admin_user_path, class: "btn btn-success"
- = render_if_exists 'admin/dashboard/users_statistics'
- .col-sm-4
- .info-well.dark-well
- .well-segment.well-centered
- = link_to admin_groups_path do
- %h3.text-center
- Groups:
- = approximate_count_with_delimiters(@counts, Group)
- %hr
- = link_to 'New group', new_admin_group_path, class: "btn btn-success"
- .row
- .col-md-4
- .info-well
- .well-segment.admin-well.admin-well-statistics
- %h4 Statistics
- %p
- Forks
- %span.light.float-right
- = approximate_fork_count_with_delimiters(@counts)
- %p
- Issues
- %span.light.float-right
- = approximate_count_with_delimiters(@counts, Issue)
- %p
- Merge Requests
- %span.light.float-right
- = approximate_count_with_delimiters(@counts, MergeRequest)
- %p
- Notes
- %span.light.float-right
- = approximate_count_with_delimiters(@counts, Note)
- %p
- Snippets
- %span.light.float-right
- = approximate_count_with_delimiters(@counts, Snippet)
- %p
- SSH Keys
- %span.light.float-right
- = approximate_count_with_delimiters(@counts, Key)
- %p
- Milestones
- %span.light.float-right
- = approximate_count_with_delimiters(@counts, Milestone)
- %p
- Active Users
- %span.light.float-right
- = number_with_delimiter(User.active.count)
- .col-md-4
- .info-well
- .well-segment.admin-well.admin-well-features
- %h4 Features
- = feature_entry(_('Sign up'), href: admin_application_settings_path(anchor: 'js-signup-settings'))
- = feature_entry(_('LDAP'), enabled: Gitlab.config.ldap.enabled)
- = feature_entry(_('Gravatar'), href: admin_application_settings_path(anchor: 'js-account-settings'), enabled: gravatar_enabled?)
- = feature_entry(_('OmniAuth'), href: admin_application_settings_path(anchor: 'js-signin-settings'), enabled: Gitlab::Auth.omniauth_enabled?)
- = feature_entry(_('Reply by email'), enabled: Gitlab::IncomingEmail.enabled?)
+.admin-dashboard.prepend-top-default
+ .row
+ .col-sm-4
+ .info-well.dark-well
+ .well-segment.well-centered
+ = link_to admin_projects_path do
+ %h3.text-center
+ Projects:
+ = approximate_count_with_delimiters(@counts, Project)
+ %hr
+ = link_to('New project', new_project_path, class: "btn btn-success")
+ .col-sm-4
+ .info-well.dark-well
+ .well-segment.well-centered
+ = link_to admin_users_path do
+ %h3.text-center
+ Users:
+ = approximate_count_with_delimiters(@counts, User)
+ %hr
+ .btn-group.d-flex{ role: 'group' }
+ = link_to 'New user', new_admin_user_path, class: "btn btn-success"
+ = render_if_exists 'admin/dashboard/users_statistics'
+ .col-sm-4
+ .info-well.dark-well
+ .well-segment.well-centered
+ = link_to admin_groups_path do
+ %h3.text-center
+ Groups:
+ = approximate_count_with_delimiters(@counts, Group)
+ %hr
+ = link_to 'New group', new_admin_group_path, class: "btn btn-success"
+ .row
+ .col-md-4
+ .info-well
+ .well-segment.admin-well.admin-well-statistics
+ %h4 Statistics
+ %p
+ Forks
+ %span.light.float-right
+ = approximate_fork_count_with_delimiters(@counts)
+ %p
+ Issues
+ %span.light.float-right
+ = approximate_count_with_delimiters(@counts, Issue)
+ %p
+ Merge Requests
+ %span.light.float-right
+ = approximate_count_with_delimiters(@counts, MergeRequest)
+ %p
+ Notes
+ %span.light.float-right
+ = approximate_count_with_delimiters(@counts, Note)
+ %p
+ Snippets
+ %span.light.float-right
+ = approximate_count_with_delimiters(@counts, Snippet)
+ %p
+ SSH Keys
+ %span.light.float-right
+ = approximate_count_with_delimiters(@counts, Key)
+ %p
+ Milestones
+ %span.light.float-right
+ = approximate_count_with_delimiters(@counts, Milestone)
+ %p
+ Active Users
+ %span.light.float-right
+ = number_with_delimiter(User.active.count)
+ .col-md-4
+ .info-well
+ .well-segment.admin-well.admin-well-features
+ %h4 Features
+ = feature_entry(_('Sign up'), href: admin_application_settings_path(anchor: 'js-signup-settings'))
+ = feature_entry(_('LDAP'), enabled: Gitlab.config.ldap.enabled)
+ = feature_entry(_('Gravatar'), href: admin_application_settings_path(anchor: 'js-account-settings'), enabled: gravatar_enabled?)
+ = feature_entry(_('OmniAuth'), href: admin_application_settings_path(anchor: 'js-signin-settings'), enabled: Gitlab::Auth.omniauth_enabled?)
+ = feature_entry(_('Reply by email'), enabled: Gitlab::IncomingEmail.enabled?)
- = render_if_exists 'admin/dashboard/elastic_and_geo'
+ = render_if_exists 'admin/dashboard/elastic_and_geo'
- = feature_entry(_('Container Registry'), href: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'), enabled: Gitlab.config.registry.enabled)
- = feature_entry(_('Gitlab Pages'), href: help_instance_configuration_url, enabled: Gitlab.config.pages.enabled)
- = feature_entry(_('Shared Runners'), href: admin_runners_path, enabled: Gitlab.config.gitlab_ci.shared_runners_enabled)
- .col-md-4
- .info-well
- .well-segment.admin-well
- %h4
- Components
- - if Gitlab::CurrentSettings.version_check_enabled
- .float-right
- = version_status_badge
- %p
- %a{ href: admin_application_settings_path }
- GitLab
+ = feature_entry(_('Container Registry'), href: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'), enabled: Gitlab.config.registry.enabled)
+ = feature_entry(_('Gitlab Pages'), href: help_instance_configuration_url, enabled: Gitlab.config.pages.enabled)
+ = feature_entry(_('Shared Runners'), href: admin_runners_path, enabled: Gitlab.config.gitlab_ci.shared_runners_enabled)
+ .col-md-4
+ .info-well
+ .well-segment.admin-well
+ %h4
+ Components
+ - if Gitlab::CurrentSettings.version_check_enabled
+ .float-right
+ = version_status_badge
+ %p
+ %a{ href: admin_application_settings_path }
+ GitLab
+ %span.float-right
+ = Gitlab::VERSION
+ = "(#{Gitlab.revision})"
+ %p
+ GitLab Shell
+ %span.float-right
+ = Gitlab::Shell.new.version
+ %p
+ GitLab Workhorse
+ %span.float-right
+ = gitlab_workhorse_version
+ %p
+ GitLab API
+ %span.float-right
+ = API::API::version
+ - if Gitlab.config.pages.enabled
+ %p
+ GitLab Pages
%span.float-right
- = Gitlab::VERSION
- = "(#{Gitlab.revision})"
- %p
- GitLab Shell
- %span.float-right
- = Gitlab::Shell.new.version
- %p
- GitLab Workhorse
- %span.float-right
- = gitlab_workhorse_version
- %p
- GitLab API
- %span.float-right
- = API::API::version
- - if Gitlab.config.pages.enabled
- %p
- GitLab Pages
- %span.float-right
- = Gitlab::Pages::VERSION
+ = Gitlab::Pages::VERSION
- = render_if_exists 'admin/dashboard/geo'
+ = render_if_exists 'admin/dashboard/geo'
- %p
- Ruby
- %span.float-right
- #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
- %p
- Rails
- %span.float-right
- #{Rails::VERSION::STRING}
- %p
- = Gitlab::Database.human_adapter_name
- %span.float-right
- = Gitlab::Database.version
- %p
- = link_to "Gitaly Servers", admin_gitaly_servers_path
- .row
- .col-md-4
- .info-well
- .well-segment.admin-well
- %h4 Latest projects
- - @projects.each do |project|
- %p
- = link_to project.full_name, admin_project_path(project), class: 'str-truncated-60'
- %span.light.float-right
- #{time_ago_with_tooltip(project.created_at)}
- .col-md-4
- .info-well
- .well-segment.admin-well
- %h4 Latest users
- - @users.each do |user|
- %p
- = link_to [:admin, user], class: 'str-truncated-60' do
- = user.name
- %span.light.float-right
- #{time_ago_with_tooltip(user.created_at)}
- .col-md-4
- .info-well
- .well-segment.admin-well
- %h4 Latest groups
- - @groups.each do |group|
- %p
- = link_to [:admin, group], class: 'str-truncated-60' do
- = group.full_name
- %span.light.float-right
- #{time_ago_with_tooltip(group.created_at)}
+ %p
+ Ruby
+ %span.float-right
+ #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
+ %p
+ Rails
+ %span.float-right
+ #{Rails::VERSION::STRING}
+ %p
+ = Gitlab::Database.human_adapter_name
+ %span.float-right
+ = Gitlab::Database.version
+ %p
+ = link_to "Gitaly Servers", admin_gitaly_servers_path
+ .row
+ .col-md-4
+ .info-well
+ .well-segment.admin-well
+ %h4 Latest projects
+ - @projects.each do |project|
+ %p
+ = link_to project.full_name, admin_project_path(project), class: 'str-truncated-60'
+ %span.light.float-right
+ #{time_ago_with_tooltip(project.created_at)}
+ .col-md-4
+ .info-well
+ .well-segment.admin-well
+ %h4 Latest users
+ - @users.each do |user|
+ %p
+ = link_to [:admin, user], class: 'str-truncated-60' do
+ = user.name
+ %span.light.float-right
+ #{time_ago_with_tooltip(user.created_at)}
+ .col-md-4
+ .info-well
+ .well-segment.admin-well
+ %h4 Latest groups
+ - @groups.each do |group|
+ %p
+ = link_to [:admin, group], class: 'str-truncated-60' do
+ = group.full_name
+ %span.light.float-right
+ #{time_ago_with_tooltip(group.created_at)}
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index cb833ffd9ac..434b6e3a37e 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -1,20 +1,18 @@
-- @no_container = true
- page_title _("Groups")
-%div{ class: container_class }
- .top-area
- .prepend-top-default.append-bottom-default
- = form_tag admin_groups_path, method: :get, class: 'js-search-form' do |f|
- = hidden_field_tag :sort, @sort
- .search-holder
- - project_name = params[:name].present? ? params[:name] : nil
- .search-field-holder
- = search_field_tag :name, project_name, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name'
- = icon("search", class: "search-icon")
- = render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash
- = link_to new_admin_group_path, class: "btn btn-success" do
- = _('New group')
- %ul.content-list
- = render @groups
+.top-area
+ .prepend-top-default.append-bottom-default
+ = form_tag admin_groups_path, method: :get, class: 'js-search-form' do |f|
+ = hidden_field_tag :sort, @sort
+ .search-holder
+ - project_name = params[:name].present? ? params[:name] : nil
+ .search-field-holder
+ = search_field_tag :name, project_name, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name'
+ = icon("search", class: "search-icon")
+ = render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash
+ = link_to new_admin_group_path, class: "btn btn-success" do
+ = _('New group')
+%ul.content-list
+ = render @groups
- = paginate @groups, theme: "gitlab"
+= paginate @groups, theme: "gitlab"
diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml
index ac56e354a4d..587bfba8d47 100644
--- a/app/views/admin/health_check/show.html.haml
+++ b/app/views/admin/health_check/show.html.haml
@@ -1,41 +1,39 @@
-- @no_container = true
- page_title _('Health Check')
- no_errors = @errors.blank?
-%div{ class: container_class }
- %h3.page-title= page_title
- .bs-callout.clearfix
- .float-left
- %p
- #{ s_('HealthCheck|Access token is') }
- %code#health-check-token= Gitlab::CurrentSettings.health_check_access_token
- .prepend-top-10
- = button_to _("Reset health check access token"), reset_health_check_token_admin_application_settings_path,
- method: :put, class: 'btn btn-default',
- data: { confirm: _('Are you sure you want to reset the health check token?') }
- %p.light
- #{ _('Health information can be retrieved from the following endpoints. More information is available') }
- = link_to s_('More information is available|here'), help_page_path('user/admin_area/monitoring/health_check')
- %ul
- %li
- %code= readiness_url(token: Gitlab::CurrentSettings.health_check_access_token)
- %li
- %code= liveness_url(token: Gitlab::CurrentSettings.health_check_access_token)
- %li
- %code= metrics_url(token: Gitlab::CurrentSettings.health_check_access_token)
- = render_if_exists 'admin/health_check/health_check_url'
- %hr
- .card
- .card-header
- Current Status:
- - if no_errors
- = icon('circle', class: 'cgreen')
- #{ s_('HealthCheck|Healthy') }
- - else
- = icon('warning', class: 'cred')
- #{ s_('HealthCheck|Unhealthy') }
- .card-body
- - if no_errors
- #{ s_('HealthCheck|No Health Problems Detected') }
- - else
- = @errors
+%h3.page-title= page_title
+.bs-callout.clearfix
+ .float-left
+ %p
+ #{ s_('HealthCheck|Access token is') }
+ %code#health-check-token= Gitlab::CurrentSettings.health_check_access_token
+ .prepend-top-10
+ = button_to _("Reset health check access token"), reset_health_check_token_admin_application_settings_path,
+ method: :put, class: 'btn btn-default',
+ data: { confirm: _('Are you sure you want to reset the health check token?') }
+%p.light
+ #{ _('Health information can be retrieved from the following endpoints. More information is available') }
+ = link_to s_('More information is available|here'), help_page_path('user/admin_area/monitoring/health_check')
+ %ul
+ %li
+ %code= readiness_url(token: Gitlab::CurrentSettings.health_check_access_token)
+ %li
+ %code= liveness_url(token: Gitlab::CurrentSettings.health_check_access_token)
+ %li
+ %code= metrics_url(token: Gitlab::CurrentSettings.health_check_access_token)
+ = render_if_exists 'admin/health_check/health_check_url'
+%hr
+.card
+ .card-header
+ Current Status:
+ - if no_errors
+ = icon('circle', class: 'cgreen')
+ #{ s_('HealthCheck|Healthy') }
+ - else
+ = icon('warning', class: 'cred')
+ #{ s_('HealthCheck|Unhealthy') }
+ .card-body
+ - if no_errors
+ #{ s_('HealthCheck|No Health Problems Detected') }
+ - else
+ = @errors
diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml
index 4e3e2f7a475..f1bdd52b399 100644
--- a/app/views/admin/jobs/index.html.haml
+++ b/app/views/admin/jobs/index.html.haml
@@ -1,22 +1,19 @@
- breadcrumb_title "Jobs"
-- @no_container = true
-%div{ class: container_class }
+.top-area.scrolling-tabs-container.inner-page-scroll-tabs
+ - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) }
+ = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
- .top-area.scrolling-tabs-container.inner-page-scroll-tabs
- - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) }
- = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
+ - if @all_builds.running_or_pending.any?
+ #stop-jobs-modal
+ .nav-controls
+ %button#stop-jobs-button.btn.btn-danger{ data: { toggle: 'modal',
+ target: '#stop-jobs-modal',
+ url: cancel_all_admin_jobs_path } }
+ = s_('AdminArea|Stop all jobs')
- - if @all_builds.running_or_pending.any?
- #stop-jobs-modal
- .nav-controls
- %button#stop-jobs-button.btn.btn-danger{ data: { toggle: 'modal',
- target: '#stop-jobs-modal',
- url: cancel_all_admin_jobs_path } }
- = s_('AdminArea|Stop all jobs')
+.row-content-block.second-block
+ #{(@scope || 'all').capitalize} jobs
- .row-content-block.second-block
- #{(@scope || 'all').capitalize} jobs
-
- %ul.content-list.builds-content-list.admin-builds-table
- = render "projects/jobs/table", builds: @builds, admin: true
+%ul.content-list.builds-content-list.admin-builds-table
+ = render "projects/jobs/table", builds: @builds, admin: true
diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml
index e4c0382a437..eb93f645ea6 100644
--- a/app/views/admin/logs/show.html.haml
+++ b/app/views/admin/logs/show.html.haml
@@ -1,26 +1,24 @@
-- @no_container = true
- page_title "Logs"
-%div{ class: container_class }
- %ul.nav-links.log-tabs.nav.nav-tabs
- - @loggers.each do |klass|
- %li.nav-item
- = link_to klass.file_name, "##{klass.file_name_noext}", data: { toggle: 'tab' }, class: "#{active_when(klass == @loggers.first)} nav-link"
- .row-content-block
- To prevent performance issues admin logs output the last 2000 lines
- .tab-content
- - @loggers.each do |klass|
- .tab-pane{ class: active_when(klass == @loggers.first), id: klass.file_name_noext }
- .file-holder#README
- .js-file-title.file-title
- %i.fa.fa-file
- = klass.file_name
- .float-right
- = link_to '#', class: 'log-bottom' do
- %i.fa.fa-arrow-down
- Scroll down
- .file-content.logs
- %ol
- - klass.read_latest.each do |line|
- %li
- %p= line
+%ul.nav-links.log-tabs.nav.nav-tabs
+ - @loggers.each do |klass|
+ %li.nav-item
+ = link_to klass.file_name, "##{klass.file_name_noext}", data: { toggle: 'tab' }, class: "#{active_when(klass == @loggers.first)} nav-link"
+.row-content-block
+ To prevent performance issues admin logs output the last 2000 lines
+.tab-content
+ - @loggers.each do |klass|
+ .tab-pane{ class: active_when(klass == @loggers.first), id: klass.file_name_noext }
+ .file-holder#README
+ .js-file-title.file-title
+ %i.fa.fa-file
+ = klass.file_name
+ .float-right
+ = link_to '#', class: 'log-bottom' do
+ %i.fa.fa-arrow-down
+ Scroll down
+ .file-content.logs
+ %ol
+ - klass.read_latest.each do |line|
+ %li
+ %p= line
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index b88b760536d..7e03eb4f075 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -1,44 +1,41 @@
-- @no_container = true
- page_title "Projects"
- params[:visibility_level] ||= []
+.top-area.scrolling-tabs-container.inner-page-scroll-tabs
+ .prepend-top-default
+ .search-holder
+ = render 'shared/projects/search_form', autofocus: true, icon: true, admin_view: true
+ .dropdown
+ - toggle_text = 'Namespace'
+ - if params[:namespace_id].present?
+ = hidden_field_tag :namespace_id, params[:namespace_id]
+ - namespace = Namespace.find(params[:namespace_id])
+ - toggle_text = "#{namespace.kind}: #{namespace.full_path}"
+ = dropdown_toggle(toggle_text, { toggle: 'dropdown', is_filter: 'true' }, { toggle_class: 'js-namespace-select large' })
+ .dropdown-menu.dropdown-select.dropdown-menu-right
+ = dropdown_title('Namespaces')
+ = dropdown_filter("Search for Namespace")
+ = dropdown_content
+ = dropdown_loading
+ = render 'shared/projects/dropdown'
+ = link_to new_project_path, class: 'btn btn-success' do
+ New Project
+ = button_tag "Search", class: "btn btn-primary btn-search hide"
-%div{ class: container_class }
- .top-area.scrolling-tabs-container.inner-page-scroll-tabs
- .prepend-top-default
- .search-holder
- = render 'shared/projects/search_form', autofocus: true, icon: true, admin_view: true
- .dropdown
- - toggle_text = 'Namespace'
- - if params[:namespace_id].present?
- = hidden_field_tag :namespace_id, params[:namespace_id]
- - namespace = Namespace.find(params[:namespace_id])
- - toggle_text = "#{namespace.kind}: #{namespace.full_path}"
- = dropdown_toggle(toggle_text, { toggle: 'dropdown', is_filter: 'true' }, { toggle_class: 'js-namespace-select large' })
- .dropdown-menu.dropdown-select.dropdown-menu-right
- = dropdown_title('Namespaces')
- = dropdown_filter("Search for Namespace")
- = dropdown_content
- = dropdown_loading
- = render 'shared/projects/dropdown'
- = link_to new_project_path, class: 'btn btn-success' do
- New Project
- = button_tag "Search", class: "btn btn-primary btn-search hide"
+ %ul.nav-links.nav.nav-tabs
+ - opts = params[:visibility_level].present? ? {} : { page: admin_projects_path }
+ = nav_link(opts) do
+ = link_to admin_projects_path do
+ All
- %ul.nav-links.nav.nav-tabs
- - opts = params[:visibility_level].present? ? {} : { page: admin_projects_path }
- = nav_link(opts) do
- = link_to admin_projects_path do
- All
+ = nav_link(html_options: { class: active_when(params[:visibility_level] == Gitlab::VisibilityLevel::PRIVATE.to_s) }) do
+ = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PRIVATE) do
+ Private
+ = nav_link(html_options: { class: active_when(params[:visibility_level] == Gitlab::VisibilityLevel::INTERNAL.to_s) }) do
+ = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::INTERNAL) do
+ Internal
+ = nav_link(html_options: { class: active_when(params[:visibility_level] == Gitlab::VisibilityLevel::PUBLIC.to_s) }) do
+ = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC) do
+ Public
- = nav_link(html_options: { class: active_when(params[:visibility_level] == Gitlab::VisibilityLevel::PRIVATE.to_s) }) do
- = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PRIVATE) do
- Private
- = nav_link(html_options: { class: active_when(params[:visibility_level] == Gitlab::VisibilityLevel::INTERNAL.to_s) }) do
- = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::INTERNAL) do
- Internal
- = nav_link(html_options: { class: active_when(params[:visibility_level] == Gitlab::VisibilityLevel::PUBLIC.to_s) }) do
- = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC) do
- Public
-
- = render 'projects'
+= render 'projects'
diff --git a/app/views/admin/requests_profiles/index.html.haml b/app/views/admin/requests_profiles/index.html.haml
index 86bfeef580c..efc16bb4d3b 100644
--- a/app/views/admin/requests_profiles/index.html.haml
+++ b/app/views/admin/requests_profiles/index.html.haml
@@ -1,26 +1,24 @@
-- @no_container = true
- page_title 'Requests Profiles'
-%div{ class: container_class }
- %h3.page-title
- = page_title
+%h3.page-title
+ = page_title
- .bs-callout.clearfix
- Pass the header
- %code X-Profile-Token: #{@profile_token}
- to profile the request
+.bs-callout.clearfix
+ Pass the header
+ %code X-Profile-Token: #{@profile_token}
+ to profile the request
- - if @profiles.present?
- .prepend-top-default
- - @profiles.each do |path, profiles|
- .card.card-small
- .card-header
- %code= path
- %ul.content-list
- - profiles.each do |profile|
- %li
- = link_to profile.time.to_s(:long) + ' ' + profile.profile_mode.capitalize,
- admin_requests_profile_path(profile)
- - else
- %p
- No profiles found
+- if @profiles.present?
+ .prepend-top-default
+ - @profiles.each do |path, profiles|
+ .card.card-small
+ .card-header
+ %code= path
+ %ul.content-list
+ - profiles.each do |profile|
+ %li
+ = link_to profile.time.to_s(:long) + ' ' + profile.profile_mode.capitalize,
+ admin_requests_profile_path(profile)
+- else
+ %p
+ No profiles found
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 5129f5d193b..76af4189b5b 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -1,96 +1,87 @@
- breadcrumb_title _('Runners')
-- @no_container = true
-%div{ class: container_class }
- .row
- .col-sm-6
- .bs-callout
- %p
- = (_"A 'Runner' is a process which runs a job. You can set up as many Runners as you need.")
- %br
- = _('Runners can be placed on separate users, servers, even on your local machine.')
- %br
+.row
+ .col-sm-6
+ .bs-callout
+ %p
+ = (_"A 'Runner' is a process which runs a job. You can set up as many Runners as you need.")
+ %br
+ = _('Runners can be placed on separate users, servers, even on your local machine.')
+ %br
- %div
- %span= _('Each Runner can be in one of the following states:')
- %ul
- %li
- %span.badge.badge-success shared
- \-
- = _('Runner runs jobs from all unassigned projects')
- %li
- %span.badge.badge-success group
- \-
- = _('Runner runs jobs from all unassigned projects in its group')
- %li
- %span.badge.badge-info specific
- \-
- = _('Runner runs jobs from assigned projects')
- %li
- %span.badge.badge-warning locked
- \-
- = _('Runner cannot be assigned to other projects')
- %li
- %span.badge.badge-danger paused
- \-
- = _('Runner will not receive any new jobs')
+ %div
+ %span= _('Each Runner can be in one of the following states:')
+ %ul
+ %li
+ %span.badge.badge-success shared
+ \-
+ = _('Runner runs jobs from all unassigned projects')
+ %li
+ %span.badge.badge-success group
+ \-
+ = _('Runner runs jobs from all unassigned projects in its group')
+ %li
+ %span.badge.badge-info specific
+ \-
+ = _('Runner runs jobs from assigned projects')
+ %li
+ %span.badge.badge-warning locked
+ \-
+ = _('Runner cannot be assigned to other projects')
+ %li
+ %span.badge.badge-danger paused
+ \-
+ = _('Runner will not receive any new jobs')
- .col-sm-6
- .bs-callout
- = render partial: 'ci/runner/how_to_setup_runner',
- locals: { registration_token: Gitlab::CurrentSettings.runners_registration_token,
- type: 'shared',
- reset_token_url: reset_registration_token_admin_application_settings_path }
+ .col-sm-6
+ .bs-callout
+ = render partial: 'ci/runner/how_to_setup_runner',
+ locals: { registration_token: Gitlab::CurrentSettings.runners_registration_token,
+ type: 'shared',
+ reset_token_url: reset_registration_token_admin_application_settings_path }
- .row
- .col-sm-9
- = form_tag admin_runners_path, id: 'runners-search', method: :get, class: 'filter-form js-filter-form' do
- .filtered-search-wrapper
- .filtered-search-box
- = dropdown_tag(custom_icon('icon_history'),
- options: { wrapper_class: 'filtered-search-history-dropdown-wrapper',
- toggle_class: 'filtered-search-history-dropdown-toggle-button',
- dropdown_class: 'filtered-search-history-dropdown',
- content_class: 'filtered-search-history-dropdown-content',
- title: _('Recent searches') }) do
- .js-filtered-search-history-dropdown{ data: { full_path: admin_runners_path } }
- .filtered-search-box-input-container.droplab-dropdown
- .scroll-container
- %ul.tokens-container.list-unstyled
- %li.input-token
- %input.form-control.filtered-search{ search_filter_input_options('runners') }
- #js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown
- %ul{ data: { dropdown: true } }
- %li.filter-dropdown-item{ data: { action: 'submit' } }
- = button_tag class: %w[btn btn-link] do
- = sprite_icon('search')
- %span
- = _('Press Enter or click to search')
- %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
- %li.filter-dropdown-item
- = button_tag class: %w[btn btn-link] do
- -# Encapsulate static class name `{{icon}}` inside #{} to bypass
- -# haml lint's ClassAttributeWithStaticValue
- %svg
- %use{ 'xlink:href': "#{'{{icon}}'}" }
- %span.js-filter-hint
- {{hint}}
- %span.js-filter-tag.dropdown-light-content
- {{tag}}
-
- #js-dropdown-admin-runner-status.filtered-search-input-dropdown-menu.dropdown-menu
- %ul{ data: { dropdown: true } }
- - Ci::Runner::AVAILABLE_STATUSES.each do |status|
- %li.filter-dropdown-item{ data: { value: status } }
- = button_tag class: %w[btn btn-link] do
- = status.titleize
+.row
+ .col-sm-9
+ = form_tag admin_runners_path, id: 'runners-search', method: :get, class: 'filter-form js-filter-form' do
+ .filtered-search-wrapper
+ .filtered-search-box
+ = dropdown_tag(custom_icon('icon_history'),
+ options: { wrapper_class: 'filtered-search-history-dropdown-wrapper',
+ toggle_class: 'filtered-search-history-dropdown-toggle-button',
+ dropdown_class: 'filtered-search-history-dropdown',
+ content_class: 'filtered-search-history-dropdown-content',
+ title: _('Recent searches') }) do
+ .js-filtered-search-history-dropdown{ data: { full_path: admin_runners_path } }
+ .filtered-search-box-input-container.droplab-dropdown
+ .scroll-container
+ %ul.tokens-container.list-unstyled
+ %li.input-token
+ %input.form-control.filtered-search{ search_filter_input_options('runners') }
+ #js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown
+ %ul{ data: { dropdown: true } }
+ %li.filter-dropdown-item{ data: { action: 'submit' } }
+ = button_tag class: %w[btn btn-link] do
+ = sprite_icon('search')
+ %span
+ = _('Press Enter or click to search')
+ %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
+ %li.filter-dropdown-item
+ = button_tag class: %w[btn btn-link] do
+ -# Encapsulate static class name `{{icon}}` inside #{} to bypass
+ -# haml lint's ClassAttributeWithStaticValue
+ %svg
+ %use{ 'xlink:href': "#{'{{icon}}'}" }
+ %span.js-filter-hint
+ {{hint}}
+ %span.js-filter-tag.dropdown-light-content
+ {{tag}}
- #js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
- %ul{ data: { dropdown: true } }
- - Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
- %li.filter-dropdown-item{ data: { value: runner_type } }
- = button_tag class: %w[btn btn-link] do
- = runner_type.titleize
+ #js-dropdown-admin-runner-status.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ - Ci::Runner::AVAILABLE_STATUSES.each do |status|
+ %li.filter-dropdown-item{ data: { value: status } }
+ = button_tag class: %w[btn btn-link] do
+ = status.titleize
#js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
@@ -99,43 +90,50 @@
= button_tag class: %w[btn btn-link] do
= runner_type.titleize
- #js-dropdown-runner-tag.filtered-search-input-dropdown-menu.dropdown-menu
- %ul{ data: { dropdown: true } }
- %li.filter-dropdown-item{ data: { value: 'none' } }
- %button.btn.btn-link
- = _('No Tag')
- %li.divider.droplab-item-ignore
- %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
- %li.filter-dropdown-item
- %button.btn.btn-link.js-data-value
- %span.dropdown-light-content
- {{name}}
+ #js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ - Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
+ %li.filter-dropdown-item{ data: { value: runner_type } }
+ = button_tag class: %w[btn btn-link] do
+ = runner_type.titleize
+
+ #js-dropdown-runner-tag.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ %li.filter-dropdown-item{ data: { value: 'none' } }
+ %button.btn.btn-link
+ = _('No Tag')
+ %li.divider.droplab-item-ignore
+ %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
+ %li.filter-dropdown-item
+ %button.btn.btn-link.js-data-value
+ %span.dropdown-light-content
+ {{name}}
- = button_tag class: %w[clear-search hidden] do
- = icon('times')
- .filter-dropdown-container
- = render 'sort_dropdown'
+ = button_tag class: %w[clear-search hidden] do
+ = icon('times')
+ .filter-dropdown-container
+ = render 'sort_dropdown'
- .col-sm-3.text-right-lg
- = _('Runners currently online: %{active_runners_count}') % { active_runners_count: @active_runners_count }
+ .col-sm-3.text-right-lg
+ = _('Runners currently online: %{active_runners_count}') % { active_runners_count: @active_runners_count }
- - if @runners.any?
- .runners-content.content-list
- .table-holder
- .gl-responsive-table-row.table-row-header{ role: 'row' }
- .table-section.section-10{ role: 'rowheader' }= _('Type')
- .table-section.section-10{ role: 'rowheader' }= _('Runner token')
- .table-section.section-20{ role: 'rowheader' }= _('Description')
- .table-section.section-10{ role: 'rowheader' }= _('Version')
- .table-section.section-10{ role: 'rowheader' }= _('IP Address')
- .table-section.section-5{ role: 'rowheader' }= _('Projects')
- .table-section.section-5{ role: 'rowheader' }= _('Jobs')
- .table-section.section-10{ role: 'rowheader' }= _('Tags')
- .table-section.section-10{ role: 'rowheader' }= _('Last contact')
- .table-section.section-10{ role: 'rowheader' }
+- if @runners.any?
+ .runners-content.content-list
+ .table-holder
+ .gl-responsive-table-row.table-row-header{ role: 'row' }
+ .table-section.section-10{ role: 'rowheader' }= _('Type')
+ .table-section.section-10{ role: 'rowheader' }= _('Runner token')
+ .table-section.section-20{ role: 'rowheader' }= _('Description')
+ .table-section.section-10{ role: 'rowheader' }= _('Version')
+ .table-section.section-10{ role: 'rowheader' }= _('IP Address')
+ .table-section.section-5{ role: 'rowheader' }= _('Projects')
+ .table-section.section-5{ role: 'rowheader' }= _('Jobs')
+ .table-section.section-10{ role: 'rowheader' }= _('Tags')
+ .table-section.section-10{ role: 'rowheader' }= _('Last contact')
+ .table-section.section-10{ role: 'rowheader' }
- - @runners.each do |runner|
- = render 'admin/runners/runner', runner: runner
- = paginate @runners, theme: 'gitlab'
- - else
- .nothing-here-block= _('No runners found')
+ - @runners.each do |runner|
+ = render 'admin/runners/runner', runner: runner
+ = paginate @runners, theme: 'gitlab'
+- else
+ .nothing-here-block= _('No runners found')
diff --git a/app/views/admin/system_info/show.html.haml b/app/views/admin/system_info/show.html.haml
index b19934e028d..948a11646f7 100644
--- a/app/views/admin/system_info/show.html.haml
+++ b/app/views/admin/system_info/show.html.haml
@@ -1,37 +1,35 @@
-- @no_container = true
- page_title "System Info"
-%div{ class: container_class }
- .prepend-top-default
- .row
- .col-sm-4
- .card.bg-light.light-well
- %h4 CPU
- .data
- - if @cpus
- %h1 #{@cpus.length} cores
- - else
- = icon('warning', class: 'text-warning')
- Unable to collect CPU info
- .col-sm-4
- .card.bg-light.light-well
- %h4 Memory Usage
- .data
- - if @memory
- %h1 #{number_to_human_size(@memory.active_bytes)} / #{number_to_human_size(@memory.total_bytes)}
- - else
- = icon('warning', class: 'text-warning')
- Unable to collect memory info
- .col-sm-4
- .card.bg-light.light-well
- %h4 Disk Usage
- .data
- - @disks.each do |disk|
- %h1 #{number_to_human_size(disk[:bytes_used])} / #{number_to_human_size(disk[:bytes_total])}
- %p= disk[:disk_name]
- %p= disk[:mount_path]
- .col-sm-4
- .card.bg-light.light-well
- %h4 Uptime
- .data
- %h1= distance_of_time_in_words_to_now(Rails.application.config.booted_at)
+.prepend-top-default
+.row
+ .col-sm-4
+ .card.bg-light.light-well
+ %h4 CPU
+ .data
+ - if @cpus
+ %h1 #{@cpus.length} cores
+ - else
+ = icon('warning', class: 'text-warning')
+ Unable to collect CPU info
+ .col-sm-4
+ .card.bg-light.light-well
+ %h4 Memory Usage
+ .data
+ - if @memory
+ %h1 #{number_to_human_size(@memory.active_bytes)} / #{number_to_human_size(@memory.total_bytes)}
+ - else
+ = icon('warning', class: 'text-warning')
+ Unable to collect memory info
+ .col-sm-4
+ .card.bg-light.light-well
+ %h4 Disk Usage
+ .data
+ - @disks.each do |disk|
+ %h1 #{number_to_human_size(disk[:bytes_used])} / #{number_to_human_size(disk[:bytes_total])}
+ %p= disk[:disk_name]
+ %p= disk[:mount_path]
+ .col-sm-4
+ .card.bg-light.light-well
+ %h4 Uptime
+ .data
+ %h1= distance_of_time_in_words_to_now(Rails.application.config.booted_at)
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 6fc7ec1bb6f..36b62557fa6 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -1,79 +1,77 @@
-- @no_container = true
- page_title "Users"
-%div{ class: container_class }
- .top-area.scrolling-tabs-container.inner-page-scroll-tabs
- .fade-left
- = icon('angle-left')
- .fade-right
- = icon('angle-right')
- %ul.nav-links.nav.nav-tabs.scrolling-tabs
- = nav_link(html_options: { class: active_when(params[:filter].nil?) }) do
- = link_to admin_users_path do
- = s_('AdminUsers|Active')
- %small.badge.badge-pill= limited_counter_with_delimiter(User.active)
- = nav_link(html_options: { class: active_when(params[:filter] == 'admins') }) do
- = link_to admin_users_path(filter: "admins") do
- = s_('AdminUsers|Admins')
- %small.badge.badge-pill= limited_counter_with_delimiter(User.admins)
- = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_enabled')} filter-two-factor-enabled" }) do
- = link_to admin_users_path(filter: 'two_factor_enabled') do
- = s_('AdminUsers|2FA Enabled')
- %small.badge.badge-pill= limited_counter_with_delimiter(User.with_two_factor)
- = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_disabled')} filter-two-factor-disabled" }) do
- = link_to admin_users_path(filter: 'two_factor_disabled') do
- = s_('AdminUsers|2FA Disabled')
- %small.badge.badge-pill= limited_counter_with_delimiter(User.without_two_factor)
- = nav_link(html_options: { class: active_when(params[:filter] == 'external') }) do
- = link_to admin_users_path(filter: 'external') do
- = s_('AdminUsers|External')
- %small.badge.badge-pill= limited_counter_with_delimiter(User.external)
- = nav_link(html_options: { class: active_when(params[:filter] == 'blocked') }) do
- = link_to admin_users_path(filter: "blocked") do
- = s_('AdminUsers|Blocked')
- %small.badge.badge-pill= limited_counter_with_delimiter(User.blocked)
- = nav_link(html_options: { class: active_when(params[:filter] == 'wop') }) do
- = link_to admin_users_path(filter: "wop") do
- = s_('AdminUsers|Without projects')
- %small.badge.badge-pill= limited_counter_with_delimiter(User.without_projects)
- .nav-controls
- = render_if_exists 'admin/users/admin_email_users'
- = link_to s_('AdminUsers|New user'), new_admin_user_path, class: 'btn btn-success btn-search float-right'
+.top-area.scrolling-tabs-container.inner-page-scroll-tabs
+ .fade-left
+ = icon('angle-left')
+ .fade-right
+ = icon('angle-right')
+ %ul.nav-links.nav.nav-tabs.scrolling-tabs
+ = nav_link(html_options: { class: active_when(params[:filter].nil?) }) do
+ = link_to admin_users_path do
+ = s_('AdminUsers|Active')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.active)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'admins') }) do
+ = link_to admin_users_path(filter: "admins") do
+ = s_('AdminUsers|Admins')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.admins)
+ = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_enabled')} filter-two-factor-enabled" }) do
+ = link_to admin_users_path(filter: 'two_factor_enabled') do
+ = s_('AdminUsers|2FA Enabled')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.with_two_factor)
+ = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_disabled')} filter-two-factor-disabled" }) do
+ = link_to admin_users_path(filter: 'two_factor_disabled') do
+ = s_('AdminUsers|2FA Disabled')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.without_two_factor)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'external') }) do
+ = link_to admin_users_path(filter: 'external') do
+ = s_('AdminUsers|External')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.external)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'blocked') }) do
+ = link_to admin_users_path(filter: "blocked") do
+ = s_('AdminUsers|Blocked')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.blocked)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'wop') }) do
+ = link_to admin_users_path(filter: "wop") do
+ = s_('AdminUsers|Without projects')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.without_projects)
+ .nav-controls
+ = render_if_exists 'admin/users/admin_email_users'
+ = link_to s_('AdminUsers|New user'), new_admin_user_path, class: 'btn btn-success btn-search float-right'
- .filtered-search-block.row-content-block.border-top-0
- = form_tag admin_users_path, method: :get do
- - if params[:filter].present?
- = hidden_field_tag "filter", h(params[:filter])
- .search-holder
- .search-field-holder
- = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email or username'), class: 'form-control search-text-input js-search-input', spellcheck: false
- - if @sort.present?
- = hidden_field_tag :sort, @sort
- = icon("search", class: "search-icon")
- = button_tag s_('AdminUsers|Search users') if Rails.env.test?
- .dropdown.user-sort-dropdown
- - toggle_text = @sort.present? ? users_sort_options_hash[@sort] : sort_title_name
- = dropdown_toggle(toggle_text, { toggle: 'dropdown' })
- %ul.dropdown-menu.dropdown-menu-right
- %li.dropdown-header
- = s_('AdminUsers|Sort by')
- %li
- - users_sort_options_hash.each do |value, title|
- = link_to admin_users_path(sort: value, filter: params[:filter], search_query: params[:search_query]) do
- = title
+.filtered-search-block.row-content-block.border-top-0
+ = form_tag admin_users_path, method: :get do
+ - if params[:filter].present?
+ = hidden_field_tag "filter", h(params[:filter])
+ .search-holder
+ .search-field-holder
+ = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email or username'), class: 'form-control search-text-input js-search-input', spellcheck: false
+ - if @sort.present?
+ = hidden_field_tag :sort, @sort
+ = icon("search", class: "search-icon")
+ = button_tag s_('AdminUsers|Search users') if Rails.env.test?
+ .dropdown.user-sort-dropdown
+ - toggle_text = @sort.present? ? users_sort_options_hash[@sort] : sort_title_name
+ = dropdown_toggle(toggle_text, { toggle: 'dropdown' })
+ %ul.dropdown-menu.dropdown-menu-right
+ %li.dropdown-header
+ = s_('AdminUsers|Sort by')
+ %li
+ - users_sort_options_hash.each do |value, title|
+ = link_to admin_users_path(sort: value, filter: params[:filter], search_query: params[:search_query]) do
+ = title
- - if @users.empty?
- .nothing-here-block.border-top-0
- = s_('AdminUsers|No users found')
- - else
- .table-holder
- .thead-white.text-nowrap.gl-responsive-table-row.table-row-header{ role: 'row' }
- .table-section.section-40{ role: 'rowheader' }= _('Name')
- .table-section.section-25{ role: 'rowheader' }= _('Created on')
- .table-section.section-15{ role: 'rowheader' }= _('Last activity')
+- if @users.empty?
+ .nothing-here-block.border-top-0
+ = s_('AdminUsers|No users found')
+- else
+ .table-holder
+ .thead-white.text-nowrap.gl-responsive-table-row.table-row-header{ role: 'row' }
+ .table-section.section-40{ role: 'rowheader' }= _('Name')
+ .table-section.section-25{ role: 'rowheader' }= _('Created on')
+ .table-section.section-15{ role: 'rowheader' }= _('Last activity')
- = render partial: 'admin/users/user', collection: @users
+ = render partial: 'admin/users/user', collection: @users
- = paginate @users, theme: "gitlab"
+= paginate @users, theme: "gitlab"
#delete-user-modal
diff --git a/app/views/clusters/clusters/_configure.html.haml b/app/views/clusters/clusters/_configure.html.haml
new file mode 100644
index 00000000000..4ce00c67866
--- /dev/null
+++ b/app/views/clusters/clusters/_configure.html.haml
@@ -0,0 +1,26 @@
+%section#cluster-integration
+ - unless @cluster.status_name.in? %i/scheduled creating/
+ = render 'form'
+
+- unless @cluster.status_name.in? %i/scheduled creating/
+ = render_if_exists 'projects/clusters/prometheus_graphs'
+
+ .cluster-applications-table#js-cluster-applications
+
+ %section.settings#js-cluster-details{ class: ('expanded' if expanded) }
+ .settings-header
+ %h4= s_('ClusterIntegration|Kubernetes cluster details')
+ %button.btn.js-settings-toggle{ type: 'button' }
+ = expanded ? _('Collapse') : _('Expand')
+ %p= s_('ClusterIntegration|See and edit the details for your Kubernetes cluster')
+ .settings-content
+ = render 'clusters/platforms/kubernetes/form', cluster: @cluster, platform: @cluster.platform_kubernetes, update_cluster_url_path: clusterable.cluster_path(@cluster)
+
+ %section.settings.no-animate#js-cluster-advanced-settings{ class: ('expanded' if expanded) }
+ .settings-header
+ %h4= _('Advanced settings')
+ %button.btn.js-settings-toggle{ type: 'button' }
+ = expanded ? _('Collapse') : _('Expand')
+ %p= s_("ClusterIntegration|Advanced options on this Kubernetes cluster's integration")
+ .settings-content#advanced-settings-section
+ = render 'advanced_settings'
diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml
index 913d4caa0bc..6052e5d96f2 100644
--- a/app/views/clusters/clusters/show.html.haml
+++ b/app/views/clusters/clusters/show.html.haml
@@ -24,38 +24,19 @@
help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'),
ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-endpoint'),
ingress_dns_help_path: help_page_path('user/project/clusters/index.md', anchor: 'manually-determining-the-external-endpoint'),
+ environments_help_path: help_page_path('ci/environments', anchor: 'defining-environments'),
+ clusters_help_path: help_page_path('user/project/clusters/index.md', anchor: 'deploying-to-a-kubernetes-cluster'),
+ deploy_boards_help_path: help_page_path('user/project/deploy_boards.html', anchor: 'enabling-deploy-boards'),
manage_prometheus_path: manage_prometheus_path,
cluster_id: @cluster.id } }
.js-cluster-application-notice
.flash-container
- %section#cluster-integration
- %h4= @cluster.name
- = render 'banner'
+ %h4= @cluster.name
+ = render 'banner'
- - unless @cluster.status_name.in? %i/scheduled creating/
- = render 'form'
+ = render_if_exists 'clusters/clusters/group_cluster_environments', expanded: expanded
- - unless @cluster.status_name.in? %i/scheduled creating/
- = render_if_exists 'projects/clusters/prometheus_graphs'
-
- .cluster-applications-table#js-cluster-applications
-
- %section.settings#js-cluster-details{ class: ('expanded' if expanded) }
- .settings-header
- %h4= s_('ClusterIntegration|Kubernetes cluster details')
- %button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p= s_('ClusterIntegration|See and edit the details for your Kubernetes cluster')
- .settings-content
- = render 'clusters/platforms/kubernetes/form', cluster: @cluster, platform: @cluster.platform_kubernetes, update_cluster_url_path: clusterable.cluster_path(@cluster)
-
- %section.settings.no-animate#js-cluster-advanced-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4= _('Advanced settings')
- %button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p= s_("ClusterIntegration|Advanced options on this Kubernetes cluster's integration")
- .settings-content#advanced-settings-section
- = render 'advanced_settings'
+ - unless Gitlab.ee?
+ = render 'configure', expanded: expanded
diff --git a/app/views/clusters/clusters/user/_form.html.haml b/app/views/clusters/clusters/user/_form.html.haml
index 1d212553c3b..5507f12b73b 100644
--- a/app/views/clusters/clusters/user/_form.html.haml
+++ b/app/views/clusters/clusters/user/_form.html.haml
@@ -25,6 +25,7 @@
help: '%{help_text} %{help_link}'.html_safe % { help_text: api_url_help_text, help_link: more_info_link }
= platform_kubernetes_field.text_area :ca_cert,
+ rows: '10',
placeholder: s_('ClusterIntegration|Certificate Authority bundle (PEM format)'),
label: s_('ClusterIntegration|CA Certificate'), label_class: 'label-bold',
help: '%{help_text} %{help_link}'.html_safe % { help_text: ca_cert_help_text, help_link: more_info_link }
diff --git a/app/views/clusters/platforms/kubernetes/_form.html.haml b/app/views/clusters/platforms/kubernetes/_form.html.haml
index e50c573bd90..41701b5614a 100644
--- a/app/views/clusters/platforms/kubernetes/_form.html.haml
+++ b/app/views/clusters/platforms/kubernetes/_form.html.haml
@@ -19,7 +19,7 @@
- copy_ca_cert_btn = clipboard_button(text: platform.ca_cert, title: s_('ClusterIntegration|Copy CA Certificate'),
class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields?
- = platform_field.text_area :ca_cert, class: 'js-select-on-focus', rows: '5',
+ = platform_field.text_area :ca_cert, class: 'js-select-on-focus', rows: '10',
readonly: cluster.read_only_kubernetes_platform_fields?,
placeholder: s_('ClusterIntegration|Certificate Authority bundle (PEM format)'),
label: s_('ClusterIntegration|CA Certificate'), label_class: 'label-bold',
diff --git a/app/views/dashboard/activity.html.haml b/app/views/dashboard/activity.html.haml
index b1c192d7bad..d7306f5932d 100644
--- a/app/views/dashboard/activity.html.haml
+++ b/app/views/dashboard/activity.html.haml
@@ -1,18 +1,15 @@
- @hide_top_links = true
-- @no_container = true
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, dashboard_projects_url(rss_url_options), title: "All activity")
-
= render_dashboard_gold_trial(current_user)
- page_title "Activity"
- header_title "Activity", activity_dashboard_path
-%div{ class: container_class }
- = render "projects/last_push"
- = render 'dashboard/activity_head'
+= render "projects/last_push"
+= render 'dashboard/activity_head'
- %section.activities
- = render 'activities'
+%section.activities
+ = render 'activities'
diff --git a/app/views/dashboard/projects/index.html.haml b/app/views/dashboard/projects/index.html.haml
index 0298f539b4b..d2aa07bab22 100644
--- a/app/views/dashboard/projects/index.html.haml
+++ b/app/views/dashboard/projects/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- @hide_top_links = true
= content_for :meta_tags do
@@ -9,11 +8,10 @@
- page_title "Projects"
- header_title "Projects", dashboard_projects_path
-%div{ class: container_class }
- = render "projects/last_push"
- - if show_projects?(@projects, params)
- = render 'dashboard/projects_head'
- = render 'nav' unless Feature.enabled?(:project_list_filter_bar)
- = render 'projects'
- - else
- = render "zero_authorized_projects"
+= render "projects/last_push"
+- if show_projects?(@projects, params)
+ = render 'dashboard/projects_head'
+ = render 'nav' unless Feature.enabled?(:project_list_filter_bar)
+ = render 'projects'
+- else
+ = render "zero_authorized_projects"
diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml
index 0fcc6894b68..2924918aa4f 100644
--- a/app/views/dashboard/projects/starred.html.haml
+++ b/app/views/dashboard/projects/starred.html.haml
@@ -1,16 +1,14 @@
- @hide_top_links = true
-- @no_container = true
- breadcrumb_title _("Projects")
- page_title _("Starred Projects")
- header_title _("Projects"), dashboard_projects_path
= render_dashboard_gold_trial(current_user)
-%div{ class: container_class }
- = render "projects/last_push"
- = render 'dashboard/projects_head', project_tab_filter: :starred
+= render "projects/last_push"
+= render 'dashboard/projects_head', project_tab_filter: :starred
- - if params[:filter_projects] || any_projects?(@projects)
- = render 'projects'
- - else
- = render 'starred_empty_state'
+- if params[:filter_projects] || any_projects?(@projects)
+ = render 'projects'
+- else
+ = render 'starred_empty_state'
diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml
index a8358704b03..41c1d3e84b7 100644
--- a/app/views/groups/labels/index.html.haml
+++ b/app/views/groups/labels/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- page_title 'Labels'
- can_admin_label = can?(current_user, :admin_label, @group)
- search = params[:search]
@@ -7,24 +6,23 @@
- if labels_or_filters
#promote-label-modal
- %div{ class: container_class }
- = render 'shared/labels/nav', labels_or_filters: labels_or_filters, can_admin_label: can_admin_label
+ = render 'shared/labels/nav', labels_or_filters: labels_or_filters, can_admin_label: can_admin_label
- .labels-container.prepend-top-5
- - if @labels.any?
- .text-muted
- = _('Labels can be applied to %{features}. Group labels are available for any project within the group.') % { features: issuable_types.to_sentence }
- .other-labels
- %h5= _('Labels')
- %ul.content-list.manage-labels-list.js-other-labels
- = render partial: 'shared/label', collection: @labels, as: :label, locals: { use_label_priority: false, subject: @group }
- = paginate @labels, theme: 'gitlab'
- - elsif search.present?
- .nothing-here-block
- = _('No labels with such name or description')
- - elsif subscribed.present?
- .nothing-here-block
- = _('You do not have any subscriptions yet')
+ .labels-container.prepend-top-5
+ - if @labels.any?
+ .text-muted
+ = _('Labels can be applied to %{features}. Group labels are available for any project within the group.') % { features: issuable_types.to_sentence }
+ .other-labels
+ %h5= _('Labels')
+ %ul.content-list.manage-labels-list.js-other-labels
+ = render partial: 'shared/label', collection: @labels, as: :label, locals: { use_label_priority: false, subject: @group }
+ = paginate @labels, theme: 'gitlab'
+ - elsif search.present?
+ .nothing-here-block
+ = _('No labels with such name or description')
+ - elsif subscribed.present?
+ .nothing-here-block
+ = _('You do not have any subscriptions yet')
- else
= render 'shared/empty_states/labels'
diff --git a/app/views/groups/milestones/new.html.haml b/app/views/groups/milestones/new.html.haml
index 248cb3b0ba5..2c93b0e4efd 100644
--- a/app/views/groups/milestones/new.html.haml
+++ b/app/views/groups/milestones/new.html.haml
@@ -1,12 +1,10 @@
-- @no_container = true
- add_to_breadcrumbs _("Milestones"), group_milestones_path(@group)
- breadcrumb_title _("New")
- page_title _("Milestones"), @milestone.name, _("Milestones")
-%div{ class: container_class }
- %h3.page-title
- New Milestone
+%h3.page-title
+ New Milestone
- %hr
+%hr
- = render "form"
+= render "form"
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 255a9ad038c..0e6c16f0f06 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,11 +1,10 @@
-- @no_container = true
- breadcrumb_title _("Details")
- @content_class = "limit-container-width" unless fluid_layout
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
-%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
+%div{ class: [("limit-container-width" unless fluid_layout)] }
= render 'groups/home_panel'
.groups-listing{ data: { endpoints: { default: group_children_path(@group, format: :json), shared: group_shared_projects_path(@group, format: :json) } } }
diff --git a/app/views/instance_statistics/cohorts/index.html.haml b/app/views/instance_statistics/cohorts/index.html.haml
index e135bab10d8..c438566cb05 100644
--- a/app/views/instance_statistics/cohorts/index.html.haml
+++ b/app/views/instance_statistics/cohorts/index.html.haml
@@ -1,16 +1,14 @@
- breadcrumb_title _("Cohorts")
-- @no_container = true
-%div{ class: container_class }
- - if @cohorts
- = render 'cohorts_table'
- - else
- .bs-callout.bs-callout-warning.clearfix
- %p
- - usage_ping_path = help_page_path('user/admin_area/settings/usage_statistics', anchor: 'usage-ping')
- - usage_ping_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: usage_ping_path }
- = s_('User Cohorts are only shown when the %{usage_ping_link_start}usage ping%{usage_ping_link_end} is enabled.').html_safe % { usage_ping_link_start: usage_ping_link_start, usage_ping_link_end: '</a>'.html_safe }
- - if current_user.admin?
- - application_settings_path = admin_application_settings_path(anchor: 'usage-statistics')
- - application_settings_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: application_settings_path }
- = s_('To enable it and see User Cohorts, visit %{application_settings_link_start}application settings%{application_settings_link_end}.').html_safe % { application_settings_link_start: application_settings_link_start, application_settings_link_end: '</a>'.html_safe }
+- if @cohorts
+ = render 'cohorts_table'
+- else
+ .bs-callout.bs-callout-warning.clearfix
+ %p
+ - usage_ping_path = help_page_path('user/admin_area/settings/usage_statistics', anchor: 'usage-ping')
+ - usage_ping_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: usage_ping_path }
+ = s_('User Cohorts are only shown when the %{usage_ping_link_start}usage ping%{usage_ping_link_end} is enabled.').html_safe % { usage_ping_link_start: usage_ping_link_start, usage_ping_link_end: '</a>'.html_safe }
+ - if current_user.admin?
+ - application_settings_path = admin_application_settings_path(anchor: 'usage-statistics')
+ - application_settings_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: application_settings_path }
+ = s_('To enable it and see User Cohorts, visit %{application_settings_link_start}application settings%{application_settings_link_end}.').html_safe % { application_settings_link_start: application_settings_link_start, application_settings_link_end: '</a>'.html_safe }
diff --git a/app/views/instance_statistics/conversational_development_index/index.html.haml b/app/views/instance_statistics/conversational_development_index/index.html.haml
index 23f90b876a0..49c8fdc9630 100644
--- a/app/views/instance_statistics/conversational_development_index/index.html.haml
+++ b/app/views/instance_statistics/conversational_development_index/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- page_title _('ConvDev Index')
- usage_ping_enabled = Gitlab::CurrentSettings.usage_ping_enabled
diff --git a/app/views/layouts/_flash.html.haml b/app/views/layouts/_flash.html.haml
index 2cdaa85bdaa..d673d7164b3 100644
--- a/app/views/layouts/_flash.html.haml
+++ b/app/views/layouts/_flash.html.haml
@@ -1,10 +1,8 @@
-- extra_flash_class = local_assigns.fetch(:extra_flash_class, nil)
-
-.flash-container.flash-container-page
+.flash-container.flash-container-page.sticky
-# We currently only support `alert`, `notice`, `success`
- flash.each do |key, value|
-# Don't show a flash message if the message is nil
- if value
- %div{ class: "flash-#{key}" }
- %div{ class: "#{(container_class unless fluid_layout)} #{(extra_flash_class unless @no_container)} #{@content_class}" }
- %span= value
+ %div{ class: "flash-content flash-#{key} rounded" }
+ %span= value
+ = sprite_icon('close', size: 16, css_class: 'close-icon')
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 006334ade07..443a73f5cce 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -13,8 +13,8 @@
= render "shared/ping_consent"
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
- = render "layouts/flash", extra_flash_class: 'limit-container-width'
.d-flex
%div{ class: "#{(container_class unless @no_container)} #{@content_class}" }
.content{ id: "content-body" }
+ = render "layouts/flash", extra_flash_class: 'limit-container-width'
= yield
diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml
index b28a375e956..6a4760c3954 100644
--- a/app/views/projects/activity.html.haml
+++ b/app/views/projects/activity.html.haml
@@ -1,8 +1,4 @@
-- @no_container = true
-
- page_title _("Activity")
-%div{ class: container_class }
- = render 'projects/last_push'
-
+= render 'projects/last_push'
= render 'projects/activity'
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index ef6f5c76de6..f2215765974 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -1,44 +1,42 @@
-- @no_container = true
- project_duration = age_map_duration(@blame_groups, @project)
- page_title "Blame", @blob.path, @ref
-%div{ class: container_class }
- #blob-content-holder.tree-holder
- = render "projects/blob/breadcrumb", blob: @blob, blame: true
+#blob-content-holder.tree-holder
+ = render "projects/blob/breadcrumb", blob: @blob, blame: true
- .file-holder
- = render "projects/blob/header", blob: @blob, blame: true
- .file-blame-legend
- = render 'age_map_legend'
- .table-responsive.file-content.blame.code.js-syntax-highlight
- %table
- - current_line = 1
- - @blame_groups.each do |blame_group|
- %tr
- - commit = blame_group[:commit]
- %td.blame-commit{ class: age_map_class(commit.committed_date, project_duration) }
- .commit
- = author_avatar(commit, size: 36, has_tooltip: false)
- .commit-row-title
- %span.item-title.str-truncated-100
- = link_to_markdown commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title
- .float-right
- = link_to commit.short_id, project_commit_path(@project, commit), class: "commit-sha"
- &nbsp;
- .light
- = commit_author_link(commit, avatar: false)
- committed
- #{time_ago_with_tooltip(commit.committed_date)}
- %td.line-numbers
- - line_count = blame_group[:lines].count
- - (current_line...(current_line + line_count)).each do |i|
- %a.diff-line-num{ href: "#L#{i}", id: "L#{i}", 'data-line-number' => i }
- = icon("link")
- = i
- \
- - current_line += line_count
- %td.lines
- %pre.code.highlight
- %code
- - blame_group[:lines].each do |line|
- #{line}
+ .file-holder
+ = render "projects/blob/header", blob: @blob, blame: true
+ .file-blame-legend
+ = render 'age_map_legend'
+ .table-responsive.file-content.blame.code.js-syntax-highlight
+ %table
+ - current_line = 1
+ - @blame_groups.each do |blame_group|
+ %tr
+ - commit = blame_group[:commit]
+ %td.blame-commit{ class: age_map_class(commit.committed_date, project_duration) }
+ .commit
+ = author_avatar(commit, size: 36, has_tooltip: false)
+ .commit-row-title
+ %span.item-title.str-truncated-100
+ = link_to_markdown commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title
+ .float-right
+ = link_to commit.short_id, project_commit_path(@project, commit), class: "commit-sha"
+ &nbsp;
+ .light
+ = commit_author_link(commit, avatar: false)
+ committed
+ #{time_ago_with_tooltip(commit.committed_date)}
+ %td.line-numbers
+ - line_count = blame_group[:lines].count
+ - (current_line...(current_line + line_count)).each do |i|
+ %a.diff-line-num{ href: "#L#{i}", id: "L#{i}", 'data-line-number' => i }
+ = icon("link")
+ = i
+ \
+ - current_line += line_count
+ %td.lines
+ %pre.code.highlight
+ %code
+ - blame_group[:lines].each do |line|
+ #{line}
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
index 4520cca8cf5..51e42091ab8 100644
--- a/app/views/projects/blob/edit.html.haml
+++ b/app/views/projects/blob/edit.html.haml
@@ -1,33 +1,31 @@
- breadcrumb_title "Repository"
-- @no_container = true
- page_title "Edit", @blob.path, @ref
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/ace.js')
-%div{ class: container_class }
- - if @conflict
- .alert.alert-danger
- Someone edited the file the same time you did. Please check out
- = link_to "the file", project_blob_path(@project, tree_join(@branch_name, @file_path)), target: "_blank", rel: 'noopener noreferrer'
- and make sure your changes will not unintentionally remove theirs.
- .editor-title-row
- %h3.page-title.blob-edit-page-title
- Edit file
- = render 'template_selectors'
- .file-editor
- %ul.nav-links.no-bottom.js-edit-mode.nav.nav-tabs
- %li.active
- = link_to '#editor' do
- Write
+- if @conflict
+ .alert.alert-danger
+ Someone edited the file the same time you did. Please check out
+ = link_to "the file", project_blob_path(@project, tree_join(@branch_name, @file_path)), target: "_blank", rel: 'noopener noreferrer'
+ and make sure your changes will not unintentionally remove theirs.
+.editor-title-row
+ %h3.page-title.blob-edit-page-title
+ Edit file
+ = render 'template_selectors'
+.file-editor
+ %ul.nav-links.no-bottom.js-edit-mode.nav.nav-tabs
+ %li.active
+ = link_to '#editor' do
+ Write
- %li
- = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
- = editing_preview_title(@blob.name)
+ %li
+ = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
+ = editing_preview_title(@blob.name)
- = form_tag(project_update_blob_path(@project, @id), method: :put, class: 'js-quick-submit js-requires-input js-edit-blob-form', data: blob_editor_paths(@project)) do
- = render 'projects/blob/editor', ref: @ref, path: @path, blob_data: @blob.data
- = render 'shared/new_commit_form', placeholder: "Update #{@blob.name}"
- = hidden_field_tag 'last_commit_sha', @last_commit_sha
- = hidden_field_tag 'content', '', id: "file-content"
- = hidden_field_tag 'from_merge_request_iid', params[:from_merge_request_iid]
- = render 'projects/commit_button', ref: @ref, cancel_path: project_blob_path(@project, @id)
+ = form_tag(project_update_blob_path(@project, @id), method: :put, class: 'js-quick-submit js-requires-input js-edit-blob-form', data: blob_editor_paths(@project)) do
+ = render 'projects/blob/editor', ref: @ref, path: @path, blob_data: @blob.data
+ = render 'shared/new_commit_form', placeholder: "Update #{@blob.name}"
+ = hidden_field_tag 'last_commit_sha', @last_commit_sha
+ = hidden_field_tag 'content', '', id: "file-content"
+ = hidden_field_tag 'from_merge_request_iid', params[:from_merge_request_iid]
+ = render 'projects/commit_button', ref: @ref, cancel_path: project_blob_path(@project, @id)
diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml
index a0b0384d78d..688b8f001c3 100644
--- a/app/views/projects/blob/show.html.haml
+++ b/app/views/projects/blob/show.html.haml
@@ -1,19 +1,16 @@
- breadcrumb_title "Repository"
-- @no_container = true
-
- page_title @blob.path, @ref
-
- signatures_path = namespace_project_signatures_path(namespace_id: @project.namespace.full_path, project_id: @project.path, id: @last_commit)
+
.js-signature-container{ data: { 'signatures-path': signatures_path } }
-%div{ class: container_class }
- = render 'projects/last_push'
+= render 'projects/last_push'
- #tree-holder.tree-holder
- = render 'blob', blob: @blob
+#tree-holder.tree-holder
+ = render 'blob', blob: @blob
- - if can_modify_blob?(@blob)
- = render 'projects/blob/remove'
+ - if can_modify_blob?(@blob)
+ = render 'projects/blob/remove'
- - title = "Replace #{@blob.name}"
- = render 'projects/blob/upload', title: title, placeholder: title, button_title: 'Replace file', form_path: project_update_blob_path(@project, @id), method: :put
+ - title = "Replace #{@blob.name}"
+ = render 'projects/blob/upload', title: title, placeholder: title, button_title: 'Replace file', form_path: project_update_blob_path(@project, @id), method: :put
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 11340d12423..6bdc6f716fe 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,70 +1,68 @@
-- @no_container = true
- page_title _('Branches')
- add_to_breadcrumbs(_('Repository'), project_tree_path(@project))
-%div{ class: container_class }
- .top-area.adjust
- %ul.nav-links.issues-state-filters.nav.nav-tabs
- %li{ class: active_when(@mode == 'overview') }>
- = link_to s_('Branches|Overview'), project_branches_path(@project), title: s_('Branches|Show overview of the branches')
+.top-area.adjust
+ %ul.nav-links.issues-state-filters.nav.nav-tabs
+ %li{ class: active_when(@mode == 'overview') }>
+ = link_to s_('Branches|Overview'), project_branches_path(@project), title: s_('Branches|Show overview of the branches')
- %li{ class: active_when(@mode == 'active') }>
- = link_to s_('Branches|Active'), project_branches_filtered_path(@project, state: 'active'), title: s_('Branches|Show active branches')
+ %li{ class: active_when(@mode == 'active') }>
+ = link_to s_('Branches|Active'), project_branches_filtered_path(@project, state: 'active'), title: s_('Branches|Show active branches')
- %li{ class: active_when(@mode == 'stale') }>
- = link_to s_('Branches|Stale'), project_branches_filtered_path(@project, state: 'stale'), title: s_('Branches|Show stale branches')
+ %li{ class: active_when(@mode == 'stale') }>
+ = link_to s_('Branches|Stale'), project_branches_filtered_path(@project, state: 'stale'), title: s_('Branches|Show stale branches')
- %li{ class: active_when(!%w[overview active stale].include?(@mode)) }>
- = link_to s_('Branches|All'), project_branches_filtered_path(@project, state: 'all'), title: s_('Branches|Show all branches')
+ %li{ class: active_when(!%w[overview active stale].include?(@mode)) }>
+ = link_to s_('Branches|All'), project_branches_filtered_path(@project, state: 'all'), title: s_('Branches|Show all branches')
- .nav-controls
- = form_tag(project_branches_filtered_path(@project, state: 'all'), method: :get) do
- = search_field_tag :search, params[:search], { placeholder: s_('Branches|Filter by branch name'), id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
+ .nav-controls
+ = form_tag(project_branches_filtered_path(@project, state: 'all'), method: :get) do
+ = search_field_tag :search, params[:search], { placeholder: s_('Branches|Filter by branch name'), id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
- - unless @mode == 'overview'
- .dropdown.inline>
- %button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
- %span.light
- = branches_sort_options_hash[@sort]
- = icon('chevron-down')
- %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
- %li.dropdown-header
- = s_('Branches|Sort by')
- - branches_sort_options_hash.each do |value, title|
- %li
- = link_to title, project_branches_filtered_path(@project, state: 'all', search: params[:search], sort: value), class: ("is-active" if @sort == value)
+ - unless @mode == 'overview'
+ .dropdown.inline>
+ %button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
+ %span.light
+ = branches_sort_options_hash[@sort]
+ = icon('chevron-down')
+ %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
+ %li.dropdown-header
+ = s_('Branches|Sort by')
+ - branches_sort_options_hash.each do |value, title|
+ %li
+ = link_to title, project_branches_filtered_path(@project, state: 'all', search: params[:search], sort: value), class: ("is-active" if @sort == value)
- - if can? current_user, :push_code, @project
- = link_to project_merged_branches_path(@project),
- class: 'btn btn-inverted btn-remove has-tooltip qa-delete-merged-branches',
- title: s_("Branches|Delete all branches that are merged into '%{default_branch}'") % { default_branch: @project.repository.root_ref },
- method: :delete,
- data: { confirm: s_('Branches|Deleting the merged branches cannot be undone. Are you sure?'),
- container: 'body' } do
- = s_('Branches|Delete merged branches')
- = link_to new_project_branch_path(@project), class: 'btn btn-success' do
- = s_('Branches|New branch')
+ - if can? current_user, :push_code, @project
+ = link_to project_merged_branches_path(@project),
+ class: 'btn btn-inverted btn-remove has-tooltip qa-delete-merged-branches',
+ title: s_("Branches|Delete all branches that are merged into '%{default_branch}'") % { default_branch: @project.repository.root_ref },
+ method: :delete,
+ data: { confirm: s_('Branches|Deleting the merged branches cannot be undone. Are you sure?'),
+ container: 'body' } do
+ = s_('Branches|Delete merged branches')
+ = link_to new_project_branch_path(@project), class: 'btn btn-success' do
+ = s_('Branches|New branch')
- = render_if_exists 'projects/commits/mirror_status'
+= render_if_exists 'projects/commits/mirror_status'
- .js-branch-list{ data: { diverging_counts_endpoint: diverging_commit_counts_namespace_project_branches_path(@project.namespace, @project, format: :json) } }
- - if can?(current_user, :admin_project, @project)
- - project_settings_link = link_to s_('Branches|project settings'), project_protected_branches_path(@project)
- .row-content-block
- %h5
- = s_('Branches|Protected branches can be managed in %{project_settings_link}.').html_safe % { project_settings_link: project_settings_link }
+.js-branch-list{ data: { diverging_counts_endpoint: diverging_commit_counts_namespace_project_branches_path(@project.namespace, @project, format: :json) } }
+- if can?(current_user, :admin_project, @project)
+ - project_settings_link = link_to s_('Branches|project settings'), project_protected_branches_path(@project)
+ .row-content-block
+ %h5
+ = s_('Branches|Protected branches can be managed in %{project_settings_link}.').html_safe % { project_settings_link: project_settings_link }
- - if @mode == 'overview' && (@active_branches.any? || @stale_branches.any?)
- = render "projects/branches/panel", branches: @active_branches, state: 'active', panel_title: s_('Branches|Active branches'), show_more_text: s_('Branches|Show more active branches'), project: @project, overview_max_branches: @overview_max_branches
- = render "projects/branches/panel", branches: @stale_branches, state: 'stale', panel_title: s_('Branches|Stale branches'), show_more_text: s_('Branches|Show more stale branches'), project: @project, overview_max_branches: @overview_max_branches
+- if @mode == 'overview' && (@active_branches.any? || @stale_branches.any?)
+ = render "projects/branches/panel", branches: @active_branches, state: 'active', panel_title: s_('Branches|Active branches'), show_more_text: s_('Branches|Show more active branches'), project: @project, overview_max_branches: @overview_max_branches
+ = render "projects/branches/panel", branches: @stale_branches, state: 'stale', panel_title: s_('Branches|Stale branches'), show_more_text: s_('Branches|Show more stale branches'), project: @project, overview_max_branches: @overview_max_branches
- - elsif @branches.any?
- %ul.content-list.all-branches
- - @branches.each do |branch|
- = render "projects/branches/branch", branch: branch, merged: @merged_branch_names.include?(branch.name)
- = paginate @branches, theme: 'gitlab'
- - else
- .nothing-here-block
- = s_('Branches|No branches to show')
+- elsif @branches.any?
+ %ul.content-list.all-branches
+ - @branches.each do |branch|
+ = render "projects/branches/branch", branch: branch, merged: @merged_branch_names.include?(branch.name)
+ = paginate @branches, theme: 'gitlab'
+- else
+ .nothing-here-block
+ = s_('Branches|No branches to show')
= render 'projects/branches/delete_protected_modal'
diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml
index 34226167288..40b96ca477e 100644
--- a/app/views/projects/commit/show.html.haml
+++ b/app/views/projects/commit/show.html.haml
@@ -1,3 +1,4 @@
+-# no_container is needed here because of full width side-by-side diff view
- @no_container = true
- add_to_breadcrumbs _('Commits'), project_commits_path(@project)
- breadcrumb_title @commit.short_id
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 2db1efdd52f..e155e3758fb 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- breadcrumb_title _("Commits")
- page_title _("Commits"), @ref
@@ -6,33 +5,32 @@
= auto_discovery_link_tag(:atom, project_commits_path(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
.js-project-commits-show{ 'data-commits-limit' => @limit }
- %div{ class: container_class }
- .tree-holder
- .nav-block
- .tree-ref-container
- .tree-ref-holder
- = render 'shared/ref_switcher', destination: 'commits'
-
- %ul.breadcrumb.repo-breadcrumb
- = commits_breadcrumbs
- .tree-controls.d-none.d-sm-none.d-md-block
- - if @merge_request.present?
- .control
- = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
- - elsif create_mr_button?(@repository.root_ref, @ref)
- .control
- = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
+ .tree-holder
+ .nav-block
+ .tree-ref-container
+ .tree-ref-holder
+ = render 'shared/ref_switcher', destination: 'commits'
+ %ul.breadcrumb.repo-breadcrumb
+ = commits_breadcrumbs
+ .tree-controls.d-none.d-sm-none.d-md-block
+ - if @merge_request.present?
.control
- = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path }) do
- = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
+ = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
+ - elsif create_mr_button?(@repository.root_ref, @ref)
.control
- = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
- = icon("rss")
+ = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
+
+ .control
+ = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path }) do
+ = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
+ .control
+ = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
+ = icon("rss")
- = render_if_exists 'projects/commits/mirror_status'
+ = render_if_exists 'projects/commits/mirror_status'
- %div{ id: dom_id(@project) }
- %ol#commits-list.list-unstyled.content_list
- = render 'commits', project: @project, ref: @ref
- = spinner
+ %div{ id: dom_id(@project) }
+ %ol#commits-list.list-unstyled.content_list
+ = render 'commits', project: @project, ref: @ref
+ = spinner
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index 14c64b3534a..02f2b104ce3 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,18 +1,16 @@
-- @no_container = true
- breadcrumb_title "Compare Revisions"
- page_title "Compare"
-%div{ class: container_class }
- %h3.page-title
- = _("Compare Git revisions")
- .sub-header-block
- - example_master = capture do
- %code.ref-name master
- - example_sha = capture do
- %code.ref-name 4eedf23
- = (_("Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe
- %br
- = (_("Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision.")).html_safe
+%h3.page-title
+ = _("Compare Git revisions")
+.sub-header-block
+ - example_master = capture do
+ %code.ref-name master
+ - example_sha = capture do
+ %code.ref-name 4eedf23
+ = (_("Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe
+ %br
+ = (_("Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision.")).html_safe
- .prepend-top-20
- = render "form"
+.prepend-top-20
+ = render "form"
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 5774b48a054..51cf95dc84b 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,25 +1,23 @@
-- @no_container = true
- add_to_breadcrumbs _("Compare Revisions"), project_compare_index_path(@project)
- page_title "#{params[:from]}...#{params[:to]}"
-%div{ class: container_class }
- .sub-header-block.no-bottom-space
- = render "form"
+.sub-header-block.no-bottom-space
+ = render "form"
- - if @commits.present?
- = render "projects/commits/commit_list"
- = render "projects/diffs/diffs", diffs: @diffs, environment: @environment, diff_page_context: "is-compare"
- - else
- .card.bg-light
- .center
- %h4
- = s_("CompareBranches|There isn't anything to compare.")
- %p.slead
- - if params[:to] == params[:from]
- - source_branch = capture do
- %span.ref-name= params[:from]
- - target_branch = capture do
- %span.ref-name= params[:to]
- = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe
- - else
- = _("You'll need to use different branch names to get a valid comparison.")
+- if @commits.present?
+ = render "projects/commits/commit_list"
+ = render "projects/diffs/diffs", diffs: @diffs, environment: @environment, diff_page_context: "is-compare"
+- else
+ .card.bg-light
+ .center
+ %h4
+ = s_("CompareBranches|There isn't anything to compare.")
+ %p.slead
+ - if params[:to] == params[:from]
+ - source_branch = capture do
+ %span.ref-name= params[:from]
+ - target_branch = capture do
+ %span.ref-name= params[:to]
+ = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe
+ - else
+ = _("You'll need to use different branch names to get a valid comparison.")
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index 2b594c125f4..6b56a4ee7ab 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,7 +1,6 @@
-- @no_container = true
- page_title "Cycle Analytics"
-#cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
+#cycle-analytics{ "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data
%banner{ "v-if" => "!isOverviewDialogDismissed",
"documentation-link": help_page_path('user/project/cycle_analytics'),
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 9fa31c147eb..a9b6b397968 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,10 +1,9 @@
- @content_class = "limit-container-width" unless fluid_layout
-- @no_container = true
- breadcrumb_title _("Details")
= render partial: 'flash_messages', locals: { project: @project }
-%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
+%div{ class: [("limit-container-width" unless fluid_layout)] }
= render "home_panel"
%h4.prepend-top-0.append-bottom-8
diff --git a/app/views/projects/environments/edit.html.haml b/app/views/projects/environments/edit.html.haml
index d581bd3aeab..56af252d785 100644
--- a/app/views/projects/environments/edit.html.haml
+++ b/app/views/projects/environments/edit.html.haml
@@ -1,8 +1,6 @@
-- @no_container = true
- page_title _("Edit"), @environment.name, _("Environments")
-%div{ class: container_class }
- %h3.page-title
- = _('Edit environment')
- %hr
- = render 'form'
+%h3.page-title
+ = _('Edit environment')
+%hr
+= render 'form'
diff --git a/app/views/projects/environments/folder.html.haml b/app/views/projects/environments/folder.html.haml
index aebd176af9b..f85c57d9aa1 100644
--- a/app/views/projects/environments/folder.html.haml
+++ b/app/views/projects/environments/folder.html.haml
@@ -1,5 +1,3 @@
-- @no_container = true
- page_title _("Environments")
-#environments-folder-list-view{ data: { environments_data: environments_folder_list_view_data,
- "css-class" => container_class } }
+#environments-folder-list-view{ data: { environments_data: environments_folder_list_view_data } }
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml
index 3ec92676cde..2ba88da3375 100644
--- a/app/views/projects/environments/index.html.haml
+++ b/app/views/projects/environments/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- page_title _("Environments")
#environments-list-view{ data: { environments_data: environments_list_data,
@@ -6,5 +5,4 @@
"can-create-environment" => can?(current_user, :create_environment, @project).to_s,
"new-environment-path" => new_project_environment_path(@project),
"help-page-path" => help_page_path("ci/environments"),
- "deploy-boards-help-path" => help_page_path("user/project/deploy_boards", anchor: "enabling-deploy-boards"),
- "css-class" => container_class } }
+ "deploy-boards-help-path" => help_page_path("user/project/deploy_boards", anchor: "enabling-deploy-boards") } }
diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml
index 7b847a85686..aab30af5ed4 100644
--- a/app/views/projects/environments/metrics.html.haml
+++ b/app/views/projects/environments/metrics.html.haml
@@ -1,5 +1,4 @@
-- @no_container = true
- page_title _("Metrics for environment"), @environment.name
-.prometheus-container{ class: container_class }
+.prometheus-container
#prometheus-graphs{ data: metrics_data(@project, @environment) }
diff --git a/app/views/projects/environments/new.html.haml b/app/views/projects/environments/new.html.haml
index c1067fdff78..96edd3f0bd7 100644
--- a/app/views/projects/environments/new.html.haml
+++ b/app/views/projects/environments/new.html.haml
@@ -1,9 +1,7 @@
-- @no_container = true
- breadcrumb_title _("Environments")
- page_title _("New Environment")
-%div{ class: container_class }
- %h3.page-title
- = _("New environment")
- %hr
- = render 'form'
+%h3.page-title
+ = _("New environment")
+%hr
+= render 'form'
diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index 6100fd3ad37..75da151f329 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- add_to_breadcrumbs _("Environments"), project_environments_path(@project)
- breadcrumb_title @environment.name
- page_title _("Environments")
@@ -6,67 +5,66 @@
- content_for :page_specific_javascripts do
= stylesheet_link_tag 'page_bundles/xterm'
-%div{ class: container_class }
- - if can?(current_user, :stop_environment, @environment)
- #stop-environment-modal.modal.fade{ tabindex: -1 }
- .modal-dialog
- .modal-content
- .modal-header
- %h4.modal-title.d-flex.mw-100
- = s_("Environments|Stopping")
- %span.has-tooltip.text-truncate.ml-1.mr-1.flex-fill{ title: @environment.name, data: { container: '#stop-environment-modal' } }
- = @environment.name
- ?
- .modal-body
- %p= s_('Environments|Are you sure you want to stop this environment?')
- - unless @environment.stop_action_available?
- .warning_message
- %p= s_('Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file.').html_safe % { emphasis_start: '<strong>'.html_safe,
- emphasis_end: '</strong>'.html_safe,
- ci_config_link_start: '<a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">'.html_safe,
- ci_config_link_end: '</a>'.html_safe }
- %a{ href: 'https://docs.gitlab.com/ee/ci/environments.html#stopping-an-environment',
- target: '_blank',
- rel: 'noopener noreferrer' }
- = s_('Environments|Learn more about stopping environments')
- .modal-footer
- = button_tag _('Cancel'), type: 'button', class: 'btn btn-cancel', data: { dismiss: 'modal' }
- = button_to stop_project_environment_path(@project, @environment), class: 'btn btn-danger has-tooltip', method: :post do
- = s_('Environments|Stop environment')
+- if can?(current_user, :stop_environment, @environment)
+ #stop-environment-modal.modal.fade{ tabindex: -1 }
+ .modal-dialog
+ .modal-content
+ .modal-header
+ %h4.modal-title.d-flex.mw-100
+ = s_("Environments|Stopping")
+ %span.has-tooltip.text-truncate.ml-1.mr-1.flex-fill{ title: @environment.name, data: { container: '#stop-environment-modal' } }
+ = @environment.name
+ ?
+ .modal-body
+ %p= s_('Environments|Are you sure you want to stop this environment?')
+ - unless @environment.stop_action_available?
+ .warning_message
+ %p= s_('Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file.').html_safe % { emphasis_start: '<strong>'.html_safe,
+ emphasis_end: '</strong>'.html_safe,
+ ci_config_link_start: '<a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">'.html_safe,
+ ci_config_link_end: '</a>'.html_safe }
+ %a{ href: 'https://docs.gitlab.com/ee/ci/environments.html#stopping-an-environment',
+ target: '_blank',
+ rel: 'noopener noreferrer' }
+ = s_('Environments|Learn more about stopping environments')
+ .modal-footer
+ = button_tag _('Cancel'), type: 'button', class: 'btn btn-cancel', data: { dismiss: 'modal' }
+ = button_to stop_project_environment_path(@project, @environment), class: 'btn btn-danger has-tooltip', method: :post do
+ = s_('Environments|Stop environment')
- .top-area
- %h3.page-title= @environment.name
- .nav-controls.ml-auto.my-2
- = render 'projects/environments/terminal_button', environment: @environment
- = render 'projects/environments/external_url', environment: @environment
- = render 'projects/environments/metrics_button', environment: @environment
- - if can?(current_user, :update_environment, @environment)
- = link_to _('Edit'), edit_project_environment_path(@project, @environment), class: 'btn'
- - if can?(current_user, :stop_environment, @environment)
- = button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal',
- target: '#stop-environment-modal' } do
- = sprite_icon('stop')
- = s_('Environments|Stop')
+.top-area
+ %h3.page-title= @environment.name
+ .nav-controls.ml-auto.my-2
+ = render 'projects/environments/terminal_button', environment: @environment
+ = render 'projects/environments/external_url', environment: @environment
+ = render 'projects/environments/metrics_button', environment: @environment
+ - if can?(current_user, :update_environment, @environment)
+ = link_to _('Edit'), edit_project_environment_path(@project, @environment), class: 'btn'
+ - if can?(current_user, :stop_environment, @environment)
+ = button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal',
+ target: '#stop-environment-modal' } do
+ = sprite_icon('stop')
+ = s_('Environments|Stop')
- .environments-container
- - if @deployments.blank?
- .empty-state
- .text-content
- %h4.state-title
- = _("You don't have any deployments right now.")
- %p.blank-state-text
- = _("Define environments in the deploy stage(s) in <code>.gitlab-ci.yml</code> to track deployments here.").html_safe
- .text-center
- = link_to _("Read more"), help_page_path("ci/environments"), class: "btn btn-success"
- - else
- .table-holder
- .ci-table.environments{ role: 'grid' }
- .gl-responsive-table-row.table-row-header{ role: 'row' }
- .table-section.section-10{ role: 'columnheader' }= _('ID')
- .table-section.section-30{ role: 'columnheader' }= _('Commit')
- .table-section.section-25{ role: 'columnheader' }= _('Job')
- .table-section.section-15{ role: 'columnheader' }= _('Created')
+.environments-container
+ - if @deployments.blank?
+ .empty-state
+ .text-content
+ %h4.state-title
+ = _("You don't have any deployments right now.")
+ %p.blank-state-text
+ = _("Define environments in the deploy stage(s) in <code>.gitlab-ci.yml</code> to track deployments here.").html_safe
+ .text-center
+ = link_to _("Read more"), help_page_path("ci/environments"), class: "btn btn-success"
+ - else
+ .table-holder
+ .ci-table.environments{ role: 'grid' }
+ .gl-responsive-table-row.table-row-header{ role: 'row' }
+ .table-section.section-10{ role: 'columnheader' }= _('ID')
+ .table-section.section-30{ role: 'columnheader' }= _('Commit')
+ .table-section.section-25{ role: 'columnheader' }= _('Job')
+ .table-section.section-15{ role: 'columnheader' }= _('Created')
- = render @deployments
+ = render @deployments
- = paginate @deployments, theme: 'gitlab'
+ = paginate @deployments, theme: 'gitlab'
diff --git a/app/views/projects/environments/terminal.html.haml b/app/views/projects/environments/terminal.html.haml
index e837d3d56ac..3a705d736f3 100644
--- a/app/views/projects/environments/terminal.html.haml
+++ b/app/views/projects/environments/terminal.html.haml
@@ -1,23 +1,21 @@
-- @no_container = true
- page_title _("Terminal for environment"), @environment.name
- content_for :page_specific_javascripts do
= stylesheet_link_tag "xterm.css"
-%div{ class: container_class }
- .top-area
- .row
- .col-sm-6
- %h3.page-title
- = _("Terminal for environment")
- = @environment.name
+.top-area
+ .row
+ .col-sm-6
+ %h3.page-title
+ = _("Terminal for environment")
+ = @environment.name
- .col-sm-6
- .nav-controls
- - if @environment.external_url.present?
- = link_to @environment.external_url, class: 'btn btn-default', target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('external-link')
- = render 'projects/deployments/actions', deployment: @environment.last_deployment
+ .col-sm-6
+ .nav-controls
+ - if @environment.external_url.present?
+ = link_to @environment.external_url, class: 'btn btn-default', target: '_blank', rel: 'noopener noreferrer nofollow' do
+ = sprite_icon('external-link')
+ = render 'projects/deployments/actions', deployment: @environment.last_deployment
.terminal-container{ class: container_class }
#terminal{ data: { project_path: "#{terminal_project_environment_path(@project, @environment)}.ws" } }
diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml
index 60160f521ad..2a2ccf8a6de 100644
--- a/app/views/projects/graphs/charts.html.haml
+++ b/app/views/projects/graphs/charts.html.haml
@@ -1,7 +1,6 @@
-- @no_container = true
- page_title _("Contribution Charts")
-.repo-charts{ class: container_class }
+.repo-charts
%h4.sub-header
= _("Programming languages used in this repository")
@@ -20,7 +19,7 @@
.col-md-8
%canvas#languages-chart{ height: 400 }
-.repo-charts{ class: container_class }
+.repo-charts
.sub-header-block.border-top
.row.tree-ref-header
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 4b2417ff43b..6e5e4607232 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,7 +1,6 @@
-- @no_container = true
- page_title _('Contributors')
-.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
+.js-graphs-show{ 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
.sub-header-block
.tree-ref-holder.inline.vertical-align-middle
= render 'shared/ref_switcher', destination: 'graphs'
diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml
index 422a3a22f87..87b027a1802 100644
--- a/app/views/projects/imports/show.html.haml
+++ b/app/views/projects/imports/show.html.haml
@@ -1,5 +1,4 @@
- page_title import_in_progress_title
-- @no_container = true
- @content_class = "limit-container-width" unless fluid_layout
.save-project-loader
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 39e9e9171cf..49e482ff1df 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- @can_bulk_update = can?(current_user, :admin_issue, @project)
- page_title "Issues"
@@ -8,18 +7,17 @@
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@project.name} issues")
- if project_issues(@project).exists?
- %div{ class: (container_class) }
- .top-area
- = render 'shared/issuable/nav', type: :issues
- = render "projects/issues/nav_btns"
- = render 'shared/issuable/search_bar', type: :issues
+ .top-area
+ = render 'shared/issuable/nav', type: :issues
+ = render "projects/issues/nav_btns"
+ = render 'shared/issuable/search_bar', type: :issues
- - if @can_bulk_update
- = render 'shared/issuable/bulk_update_sidebar', type: :issues
+ - if @can_bulk_update
+ = render 'shared/issuable/bulk_update_sidebar', type: :issues
- .issues-holder
- = render 'issues'
- - if new_issue_email
- = render 'projects/issuable_by_email', email: new_issue_email, issuable_type: 'issue'
+ .issues-holder
+ = render 'issues'
+ - if new_issue_email
+ = render 'projects/issuable_by_email', email: new_issue_email, issuable_type: 'issue'
- else
= render 'shared/empty_states/issues', button_path: new_project_issue_path(@project), show_import_button: true
diff --git a/app/views/projects/jobs/index.html.haml b/app/views/projects/jobs/index.html.haml
index afea5268006..5acb2af08e4 100644
--- a/app/views/projects/jobs/index.html.haml
+++ b/app/views/projects/jobs/index.html.haml
@@ -1,18 +1,16 @@
-- @no_container = true
- page_title "Jobs"
-%div{ class: container_class }
- .top-area
- - build_path_proc = ->(scope) { project_jobs_path(@project, scope: scope) }
- = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
+.top-area
+ - build_path_proc = ->(scope) { project_jobs_path(@project, scope: scope) }
+ = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
- .nav-controls
- - if can?(current_user, :update_build, @project)
- - unless @repository.gitlab_ci_yml
- = link_to 'Get started with Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
+ .nav-controls
+ - if can?(current_user, :update_build, @project)
+ - unless @repository.gitlab_ci_yml
+ = link_to 'Get started with Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
- = link_to project_ci_lint_path(@project), class: 'btn btn-default' do
- %span CI lint
+ = link_to project_ci_lint_path(@project), class: 'btn btn-default' do
+ %span CI lint
- .content-list.builds-content-list
- = render "table", builds: @builds, project: @project
+.content-list.builds-content-list
+ = render "table", builds: @builds, project: @project
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index a3688c17041..2e322c7db23 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- add_to_breadcrumbs _("Jobs"), project_jobs_path(@project)
- breadcrumb_title "##{@build.id}"
- page_title "#{@build.name} (##{@build.id})", _("Jobs")
@@ -6,11 +5,4 @@
- content_for :page_specific_javascripts do
= stylesheet_link_tag 'page_bundles/xterm'
-%div{ class: container_class }
- #js-job-vue-app{ data: { endpoint: project_job_path(@project, @build, format: :json), project_path: @project.full_path,
- deployment_help_url: help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting-failed-deployment-jobs'),
- runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'),
- runner_settings_url: project_runners_path(@build.project, anchor: 'js-runners-settings'),
- variables_settings_url: project_variables_path(@build.project, anchor: 'js-cicd-variables-settings'),
- page_path: project_job_path(@project, @build), build_status: @build.status, build_stage: @build.stage, log_state: '',
- build_options: javascript_build_options } }
+#js-job-vue-app{ data: jobs_data }
diff --git a/app/views/projects/jobs/terminal.html.haml b/app/views/projects/jobs/terminal.html.haml
index f7e7535ee92..5439a4b5d5c 100644
--- a/app/views/projects/jobs/terminal.html.haml
+++ b/app/views/projects/jobs/terminal.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- add_to_breadcrumbs 'Jobs', project_jobs_path(@project)
- add_to_breadcrumbs "##{@build.id}", project_job_path(@project, @build)
- breadcrumb_title 'Terminal'
@@ -7,5 +6,5 @@
- content_for :page_specific_javascripts do
= stylesheet_link_tag "xterm.css"
-.terminal-container{ class: container_class }
+.terminal-container
#terminal{ data: { project_path: terminal_project_job_path(@project, @build, format: :ws) } }
diff --git a/app/views/projects/labels/edit.html.haml b/app/views/projects/labels/edit.html.haml
index b9d45e83032..b7996f0dad1 100644
--- a/app/views/projects/labels/edit.html.haml
+++ b/app/views/projects/labels/edit.html.haml
@@ -1,10 +1,8 @@
-- @no_container = true
- add_to_breadcrumbs "Labels", project_labels_path(@project)
- breadcrumb_title "Edit"
- page_title "Edit", @label.name, "Labels"
-%div{ class: container_class }
- %h3.page-title
- Edit Label
- %hr
- = render 'shared/labels/form', url: project_label_path(@project, @label), back_path: project_labels_path(@project)
+%h3.page-title
+ Edit Label
+%hr
+= render 'shared/labels/form', url: project_label_path(@project, @label), back_path: project_labels_path(@project)
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 511d7a82d1b..0328751c68c 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- page_title "Labels"
- can_admin_label = can?(current_user, :admin_label, @project)
- search = params[:search]
@@ -7,48 +6,47 @@
- if labels_or_filters
#promote-label-modal
- %div{ class: container_class }
- = render 'shared/labels/nav', labels_or_filters: labels_or_filters, can_admin_label: can_admin_label
+ = render 'shared/labels/nav', labels_or_filters: labels_or_filters, can_admin_label: can_admin_label
- .labels-container.prepend-top-10
- - if can_admin_label && search.blank?
- %p.text-muted
- = _('Labels can be applied to issues and merge requests.')
- %br
- = _('Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.')
+ .labels-container.prepend-top-10
+ - if can_admin_label && search.blank?
+ %p.text-muted
+ = _('Labels can be applied to issues and merge requests.')
+ %br
+ = _('Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.')
- -# Only show it in the first page
- - hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1')
- .prioritized-labels{ class: [('hide' if hide), ('is-not-draggable' unless can_admin_label)] }
- %h5.prepend-top-10= _('Prioritized Labels')
- .content-list.manage-labels-list.js-prioritized-labels{ data: { url: set_priorities_project_labels_path(@project), sortable: can_admin_label } }
- #js-priority-labels-empty-state.priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty? && search.blank?}" }
- = render 'shared/empty_states/priority_labels'
- - if @prioritized_labels.present?
- = render partial: 'shared/label', collection: @prioritized_labels, as: :label, locals: { force_priority: true, subject: @project }
- - elsif search.present?
- .nothing-here-block
- = _('No prioritised labels with such name or description')
+ -# Only show it in the first page
+ - hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1')
+ .prioritized-labels{ class: [('hide' if hide), ('is-not-draggable' unless can_admin_label)] }
+ %h5.prepend-top-10= _('Prioritized Labels')
+ .content-list.manage-labels-list.js-prioritized-labels{ data: { url: set_priorities_project_labels_path(@project), sortable: can_admin_label } }
+ #js-priority-labels-empty-state.priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty? && search.blank?}" }
+ = render 'shared/empty_states/priority_labels'
+ - if @prioritized_labels.present?
+ = render partial: 'shared/label', collection: @prioritized_labels, as: :label, locals: { force_priority: true, subject: @project }
+ - elsif search.present?
+ .nothing-here-block
+ = _('No prioritised labels with such name or description')
- - if @labels.present?
- .other-labels
- %h5{ class: ('hide' if hide) }= _('Other Labels')
- .content-list.manage-labels-list.js-other-labels
- = render partial: 'shared/label', collection: @labels, as: :label, locals: { subject: @project }
- = paginate @labels, theme: 'gitlab'
- - elsif search.present?
- .other-labels
- - if @available_labels.any?
- %h5
- = _('Other Labels')
- .nothing-here-block
- = _('No other labels with such name or description')
- - else
- .nothing-here-block
- = _('No labels with such name or description')
- - elsif subscribed.present?
- .nothing-here-block
- = _('You do not have any subscriptions yet')
+ - if @labels.present?
+ .other-labels
+ %h5{ class: ('hide' if hide) }= _('Other Labels')
+ .content-list.manage-labels-list.js-other-labels
+ = render partial: 'shared/label', collection: @labels, as: :label, locals: { subject: @project }
+ = paginate @labels, theme: 'gitlab'
+ - elsif search.present?
+ .other-labels
+ - if @available_labels.any?
+ %h5
+ = _('Other Labels')
+ .nothing-here-block
+ = _('No other labels with such name or description')
+ - else
+ .nothing-here-block
+ = _('No labels with such name or description')
+ - elsif subscribed.present?
+ .nothing-here-block
+ = _('You do not have any subscriptions yet')
- else
= render 'shared/empty_states/labels'
diff --git a/app/views/projects/labels/new.html.haml b/app/views/projects/labels/new.html.haml
index c6739231e36..96ce0eba2c6 100644
--- a/app/views/projects/labels/new.html.haml
+++ b/app/views/projects/labels/new.html.haml
@@ -1,10 +1,8 @@
-- @no_container = true
- add_to_breadcrumbs "Labels", project_labels_path(@project)
- breadcrumb_title "New"
- page_title "New Label"
-%div{ class: container_class }
- %h3.page-title
- New Label
- %hr
- = render 'shared/labels/form', url: project_labels_path(@project), back_path: project_labels_path(@project)
+%h3.page-title
+ New Label
+%hr
+= render 'shared/labels/form', url: project_labels_path(@project), back_path: project_labels_path(@project)
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 623380c9c61..4e30f09b9a2 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- @can_bulk_update = can?(current_user, :admin_merge_request, @project)
- merge_project = merge_request_source_project_for_project(@project)
- new_merge_request_path = project_new_merge_request_path(merge_project) if merge_project
@@ -6,24 +5,22 @@
- page_title "Merge Requests"
- new_merge_request_email = @project.new_issuable_address(current_user, 'merge_request')
-%div{ class: container_class }
- = render 'projects/last_push'
+= render 'projects/last_push'
- if @project.merge_requests.exists?
- %div{ class: container_class }
- .top-area
- = render 'shared/issuable/nav', type: :merge_requests
- .nav-controls
- = render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
+ .top-area
+ = render 'shared/issuable/nav', type: :merge_requests
+ .nav-controls
+ = render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
- = render 'shared/issuable/search_bar', type: :merge_requests
+ = render 'shared/issuable/search_bar', type: :merge_requests
- - if @can_bulk_update
- = render 'shared/issuable/bulk_update_sidebar', type: :merge_requests
+ - if @can_bulk_update
+ = render 'shared/issuable/bulk_update_sidebar', type: :merge_requests
- .merge-requests-holder
- = render 'merge_requests'
- - if new_merge_request_email
- = render 'projects/issuable_by_email', email: new_merge_request_email, issuable_type: 'merge_request'
+ .merge-requests-holder
+ = render 'merge_requests'
+ - if new_merge_request_email
+ = render 'projects/issuable_by_email', email: new_merge_request_email, issuable_type: 'merge_request'
- else
= render 'shared/empty_states/merge_requests', button_path: new_merge_request_path
diff --git a/app/views/projects/milestones/_deprecation_message.html.haml b/app/views/projects/milestones/_deprecation_message.html.haml
deleted file mode 100644
index b2cca3690d6..00000000000
--- a/app/views/projects/milestones/_deprecation_message.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-.banner-callout.compact.milestone-deprecation-message.prepend-top-20
- .banner-graphic= image_tag 'illustrations/milestone_removing-page.svg'
- .banner-body.prepend-left-10.append-right-10
- %h5.banner-title.prepend-top-0
- = _('The tabs below will be removed in a future version')
- %p.milestone-banner-text
- = _('Learn more about %{issue_boards_url}, to keep track of issues in multiple lists, using labels, assignees, and milestones. If you’re missing something from issue boards, please create an issue on %{gitlab_issues_url}.').html_safe % { issue_boards_url: link_to(_('issue boards'), help_page_url('user/project/issue_board'), target: '_blank', rel: 'noopener noreferrer'), gitlab_issues_url: link_to(_('GitLab’s issue tracker'), 'https://gitlab.com/gitlab-org/gitlab-ce/issues', target: '_blank', rel: 'noopener noreferrer') }
diff --git a/app/views/projects/milestones/edit.html.haml b/app/views/projects/milestones/edit.html.haml
index aa564e00af9..0d040a5cdb3 100644
--- a/app/views/projects/milestones/edit.html.haml
+++ b/app/views/projects/milestones/edit.html.haml
@@ -1,14 +1,10 @@
-- @no_container = true
- breadcrumb_title _('Edit')
- add_to_breadcrumbs _('Milestones'), project_milestones_path(@project)
- page_title _('Edit'), @milestone.title, _('Milestones')
+%h3.page-title
+ = _('Edit Milestone')
-%div{ class: container_class }
+%hr
- %h3.page-title
- = _('Edit Milestone')
-
- %hr
-
- = render 'form'
+= render 'form'
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index a3414c16d73..c89566dac90 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -1,26 +1,24 @@
-- @no_container = true
- page_title _('Milestones')
-%div{ class: container_class }
- .top-area
- = render 'shared/milestones_filter', counts: milestone_counts(@project.milestones)
+.top-area
+ = render 'shared/milestones_filter', counts: milestone_counts(@project.milestones)
- .nav-controls
- = render 'shared/milestones/search_form'
- = render 'shared/milestones_sort_dropdown'
- - if can?(current_user, :admin_milestone, @project)
- = link_to new_project_milestone_path(@project), class: 'btn btn-success qa-new-project-milestone', title: _('New milestone') do
- = _('New milestone')
+ .nav-controls
+ = render 'shared/milestones/search_form'
+ = render 'shared/milestones_sort_dropdown'
+ - if can?(current_user, :admin_milestone, @project)
+ = link_to new_project_milestone_path(@project), class: 'btn btn-success qa-new-project-milestone', title: _('New milestone') do
+ = _('New milestone')
- .milestones
- #delete-milestone-modal
- #promote-milestone-modal
+.milestones
+ #delete-milestone-modal
+ #promote-milestone-modal
- %ul.content-list
- = render @milestones
+ %ul.content-list
+ = render @milestones
- - if @milestones.blank?
- %li
- .nothing-here-block= _('No milestones to show')
+ - if @milestones.blank?
+ %li
+ .nothing-here-block= _('No milestones to show')
- = paginate @milestones, theme: 'gitlab'
+ = paginate @milestones, theme: 'gitlab'
diff --git a/app/views/projects/milestones/new.html.haml b/app/views/projects/milestones/new.html.haml
index 79207fd70b5..721506a2201 100644
--- a/app/views/projects/milestones/new.html.haml
+++ b/app/views/projects/milestones/new.html.haml
@@ -1,12 +1,10 @@
-- @no_container = true
- add_to_breadcrumbs _('Milestones'), project_milestones_path(@project)
- breadcrumb_title _('New')
- page_title _('New Milestone')
-%div{ class: container_class }
- %h3.page-title
- = _('New Milestone')
+%h3.page-title
+ = _('New Milestone')
- %hr
+%hr
- = render 'form'
+= render 'form'
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 1cee8be604a..49d3039d0c9 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,71 +1,68 @@
-- @no_container = true
- add_to_breadcrumbs _('Milestones'), project_milestones_path(@project)
- breadcrumb_title @milestone.title
- page_title @milestone.title, _('Milestones')
- page_description @milestone.description
-%div{ class: container_class }
- .detail-page-header.milestone-page-header
- .status-box{ class: status_box_class(@milestone) }
- - if @milestone.closed?
- = _('Closed')
- - elsif @milestone.expired?
- = _('Past due')
- - elsif @milestone.upcoming?
- = _('Upcoming')
- - else
- = _('Open')
- .header-text-content
- %span.identifier
- %strong
- = _('Milestone')
- - if @milestone.due_date || @milestone.start_date
- = milestone_date_range(@milestone)
- .milestone-buttons
- - if can?(current_user, :admin_milestone, @project)
- = link_to edit_project_milestone_path(@project, @milestone), class: 'btn btn-grouped btn-nr' do
- = _('Edit')
+.detail-page-header.milestone-page-header
+ .status-box{ class: status_box_class(@milestone) }
+ - if @milestone.closed?
+ = _('Closed')
+ - elsif @milestone.expired?
+ = _('Past due')
+ - elsif @milestone.upcoming?
+ = _('Upcoming')
+ - else
+ = _('Open')
+ .header-text-content
+ %span.identifier
+ %strong
+ = _('Milestone')
+ - if @milestone.due_date || @milestone.start_date
+ = milestone_date_range(@milestone)
+ .milestone-buttons
+ - if can?(current_user, :admin_milestone, @project)
+ = link_to edit_project_milestone_path(@project, @milestone), class: 'btn btn-grouped btn-nr' do
+ = _('Edit')
- - if @project.group
- %button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
- target: '#promote-milestone-modal',
- milestone_title: @milestone.title,
- group_name: @project.group.name,
- url: promote_project_milestone_path(@milestone.project, @milestone),
- container: 'body' },
- disabled: true,
- type: 'button' }
- = _('Promote')
- #promote-milestone-modal
+ - if @project.group
+ %button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
+ target: '#promote-milestone-modal',
+ milestone_title: @milestone.title,
+ group_name: @project.group.name,
+ url: promote_project_milestone_path(@milestone.project, @milestone),
+ container: 'body' },
+ disabled: true,
+ type: 'button' }
+ = _('Promote')
+ #promote-milestone-modal
- - if @milestone.active?
- = link_to _('Close milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: 'btn btn-close btn-nr btn-grouped'
- - else
- = link_to _('Reopen milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: 'btn btn-reopen btn-nr btn-grouped'
+ - if @milestone.active?
+ = link_to _('Close milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: 'btn btn-close btn-nr btn-grouped'
+ - else
+ = link_to _('Reopen milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: 'btn btn-reopen btn-nr btn-grouped'
- = render 'shared/milestones/delete_button'
+ = render 'shared/milestones/delete_button'
- %a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: '#' }
- = icon('angle-double-left')
+ %a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: '#' }
+ = icon('angle-double-left')
- .detail-page-description.milestone-detail
- %h2.title.qa-milestone-title
- = markdown_field(@milestone, :title)
+.detail-page-description.milestone-detail
+ %h2.title.qa-milestone-title
+ = markdown_field(@milestone, :title)
- %div
- - if @milestone.description.present?
- .description.md
- = markdown_field(@milestone, :description)
+ %div
+ - if @milestone.description.present?
+ .description.md
+ = markdown_field(@milestone, :description)
- = render_if_exists 'shared/milestones/burndown', milestone: @milestone, project: @project
+= render_if_exists 'shared/milestones/burndown', milestone: @milestone, project: @project
- - if can?(current_user, :read_issue, @project) && @milestone.total_issues_count(current_user).zero?
- .alert.alert-success.prepend-top-default
- %span= _('Assign some issues to this milestone.')
- - elsif @milestone.complete?(current_user) && @milestone.active?
- .alert.alert-success.prepend-top-default
- %span= _('All issues for this milestone are closed. You may close this milestone now.')
+- if can?(current_user, :read_issue, @project) && @milestone.total_issues_count(current_user).zero?
+ .alert.alert-success.prepend-top-default
+ %span= _('Assign some issues to this milestone.')
+- elsif @milestone.complete?(current_user) && @milestone.active?
+ .alert.alert-success.prepend-top-default
+ %span= _('All issues for this milestone are closed. You may close this milestone now.')
- = render 'deprecation_message'
- = render 'shared/milestones/tabs', milestone: @milestone
- = render 'shared/milestones/sidebar', milestone: @milestone, project: @project, affix_offset: 153
+= render 'shared/milestones/tabs', milestone: @milestone
+= render 'shared/milestones/sidebar', milestone: @milestone, project: @project, affix_offset: 153
diff --git a/app/views/projects/network/_head.html.haml b/app/views/projects/network/_head.html.haml
index f08526f485e..701cb37a1c8 100644
--- a/app/views/projects/network/_head.html.haml
+++ b/app/views/projects/network/_head.html.haml
@@ -1,9 +1,6 @@
-- @no_container = true
+.row-content-block.second-block.content-component-block
+ .tree-ref-holder
+ = render partial: 'shared/ref_switcher', locals: {destination: 'graph'}
-%div{ class: container_class }
- .row-content-block.second-block.content-component-block
- .tree-ref-holder
- = render partial: 'shared/ref_switcher', locals: {destination: 'graph'}
-
- .oneline
- = _("You can move around the graph by using the arrow keys.")
+ .oneline
+ = _("You can move around the graph by using the arrow keys.")
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 0580c15ad15..4a0be9e67cb 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -1,22 +1,20 @@
- breadcrumb_title _("Schedules")
-- @no_container = true
- page_title _("Pipeline Schedules")
-%div{ class: container_class }
- #pipeline-schedules-callout{ data: { docs_url: help_page_path('user/project/pipelines/schedules') } }
- .top-area
- - schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
- = render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
+#pipeline-schedules-callout{ data: { docs_url: help_page_path('user/project/pipelines/schedules') } }
+.top-area
+ - schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
+ = render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
- - if can?(current_user, :create_pipeline_schedule, @project)
- .nav-controls
- = link_to new_project_pipeline_schedule_path(@project), class: 'btn btn-success' do
- %span= _('New schedule')
+ - if can?(current_user, :create_pipeline_schedule, @project)
+ .nav-controls
+ = link_to new_project_pipeline_schedule_path(@project), class: 'btn btn-success' do
+ %span= _('New schedule')
- - if @schedules.present?
- %ul.content-list
- = render partial: "table"
- - else
- .card.bg-light
- .nothing-here-block= _("No schedules")
+- if @schedules.present?
+ %ul.content-list
+ = render partial: "table"
+- else
+ .card.bg-light
+ .nothing-here-block= _("No schedules")
diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml
index 6b4110e07d2..c9a50b97fea 100644
--- a/app/views/projects/pipelines/charts.html.haml
+++ b/app/views/projects/pipelines/charts.html.haml
@@ -1,10 +1,6 @@
-- @no_container = true
- page_title _('CI / CD Charts')
-%div{ class: container_class }
-
- #charts.ci-charts
- = render 'projects/pipelines/charts/overall'
-
- %hr
- = render 'projects/pipelines/charts/pipelines'
+#charts.ci-charts
+ = render 'projects/pipelines/charts/overall'
+ %hr
+ = render 'projects/pipelines/charts/pipelines'
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index 4e4638085fd..f64f07487fd 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -1,17 +1,15 @@
-- @no_container = true
- page_title _('Pipelines')
= render_if_exists "shared/shared_runners_minutes_limit_flash_message"
-%div{ 'class' => container_class }
- #pipelines-list-vue{ data: { endpoint: project_pipelines_path(@project, format: :json),
- "help-page-path" => help_page_path('ci/quick_start/README'),
- "help-auto-devops-path" => help_page_path('topics/autodevops/index.md'),
- "empty-state-svg-path" => image_path('illustrations/pipelines_empty.svg'),
- "error-state-svg-path" => image_path('illustrations/pipelines_failed.svg'),
- "no-pipelines-svg-path" => image_path('illustrations/pipelines_pending.svg'),
- "can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
- "new-pipeline-path" => can?(current_user, :create_pipeline, @project) && new_project_pipeline_path(@project),
- "ci-lint-path" => can?(current_user, :create_pipeline, @project) && project_ci_lint_path(@project),
- "reset-cache-path" => can?(current_user, :admin_pipeline, @project) && reset_cache_project_settings_ci_cd_path(@project) ,
- "has-gitlab-ci" => (@project.has_ci? && @project.builds_enabled?).to_s } }
+#pipelines-list-vue{ data: { endpoint: project_pipelines_path(@project, format: :json),
+ "help-page-path" => help_page_path('ci/quick_start/README'),
+ "help-auto-devops-path" => help_page_path('topics/autodevops/index.md'),
+ "empty-state-svg-path" => image_path('illustrations/pipelines_empty.svg'),
+ "error-state-svg-path" => image_path('illustrations/pipelines_failed.svg'),
+ "no-pipelines-svg-path" => image_path('illustrations/pipelines_pending.svg'),
+ "can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
+ "new-pipeline-path" => can?(current_user, :create_pipeline, @project) && new_project_pipeline_path(@project),
+ "ci-lint-path" => can?(current_user, :create_pipeline, @project) && project_ci_lint_path(@project),
+ "reset-cache-path" => can?(current_user, :admin_pipeline, @project) && reset_cache_project_settings_ci_cd_path(@project) ,
+ "has-gitlab-ci" => (@project.has_ci? && @project.builds_enabled?).to_s } }
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index 8a6d7b082e3..2b2133b8296 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -1,9 +1,8 @@
-- @no_container = true
- add_to_breadcrumbs _('Pipelines'), project_pipelines_path(@project)
- breadcrumb_title "##{@pipeline.id}"
- page_title _('Pipeline')
-.js-pipeline-container{ class: container_class, data: { controller_action: "#{controller.action_name}" } }
+.js-pipeline-container{ data: { controller_action: "#{controller.action_name}" } }
#js-pipeline-header-vue.pipeline-header-container
- if @pipeline.commit.present?
diff --git a/app/views/projects/project_templates/_built_in_templates.html.haml b/app/views/projects/project_templates/_built_in_templates.html.haml
index d1c09e83fd3..a583eb39eb3 100644
--- a/app/views/projects/project_templates/_built_in_templates.html.haml
+++ b/app/views/projects/project_templates/_built_in_templates.html.haml
@@ -1,5 +1,5 @@
- Gitlab::ProjectTemplate.all.each do |template|
- .template-option.d-flex.align-items-center
+ .template-option.d-flex.align-items-center{ data: { qa_selector: 'template_option_row' } }
.logo.append-right-10.px-1
= image_tag template.logo, size: 32, class: "btn-template-icon icon-#{template.name}"
.description
@@ -13,5 +13,5 @@
= _("Preview")
%label.btn.btn-success.template-button.choose-template.append-bottom-0{ for: template.name }
%input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } }
- %span
+ %span{ data: { qa_selector: 'use_template_button' } }
= _("Use template")
diff --git a/app/views/projects/releases/index.html.haml b/app/views/projects/releases/index.html.haml
index 28bb4e032eb..326b83c856e 100644
--- a/app/views/projects/releases/index.html.haml
+++ b/app/views/projects/releases/index.html.haml
@@ -1,5 +1,3 @@
-- @no_container = true
- page_title _('Releases')
-%div{ class: container_class }
- #js-releases-page{ data: { project_id: @project.id, illustration_path: image_path('illustrations/releases.svg'), documentation_path: help_page_path('user/project/releases/index') } }
+#js-releases-page{ data: { project_id: @project.id, illustration_path: image_path('illustrations/releases.svg'), documentation_path: help_page_path('user/project/releases/index') } }
diff --git a/app/views/projects/serverless/functions/index.html.haml b/app/views/projects/serverless/functions/index.html.haml
index bac6c76684b..09f4e556949 100644
--- a/app/views/projects/serverless/functions/index.html.haml
+++ b/app/views/projects/serverless/functions/index.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- @content_class = "limit-container-width" unless fluid_layout
- breadcrumb_title 'Serverless'
- page_title 'Serverless'
@@ -10,7 +9,7 @@
clusters_path: clusters_path,
help_path: help_page_path('user/project/clusters/serverless/index') } }
-%div{ class: [container_class, ('limit-container-width' unless fluid_layout)] }
+%div{ class: [('limit-container-width' unless fluid_layout)] }
.js-serverless-functions-notice
.flash-container
diff --git a/app/views/projects/serverless/functions/show.html.haml b/app/views/projects/serverless/functions/show.html.haml
index d1fe208ce60..79bb943d6ed 100644
--- a/app/views/projects/serverless/functions/show.html.haml
+++ b/app/views/projects/serverless/functions/show.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- @content_class = "limit-container-width" unless fluid_layout
- clusters_path = project_clusters_path(@project)
- help_path = help_page_path('user/project/clusters/serverless/index')
@@ -12,7 +11,7 @@
clusters_path: clusters_path,
help_path: help_path } }
-%div{ class: [container_class, ('limit-container-width' unless fluid_layout)] }
+%div{ class: [('limit-container-width' unless fluid_layout)] }
.serverless-function-details#js-serverless-function-details
.js-serverless-function-notice
diff --git a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
index 04b77fb987a..1d5d90593ae 100644
--- a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
@@ -1,3 +1,14 @@
+- has_base_domain = @project.all_clusters.any? { |cluster| cluster.base_domain && !cluster.base_domain.empty? }
+
+- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe
+- link_end = '</a>'.html_safe
+
+- kubernetes_cluster_path = help_page_path('user/project/clusters/index')
+- kubernetes_cluster_link_start = link_start % { url: kubernetes_cluster_path }
+
+- base_domain_path = help_page_path('user/project/clusters/index', anchor: 'base-domain')
+- base_domain_link_start = link_start % { url: base_domain_path }
+
.row
.col-lg-12
= form_for @project, url: project_settings_ci_cd_path(@project, anchor: 'autodevops-settings') do |f|
@@ -19,9 +30,10 @@
.card-footer.js-extra-settings{ class: auto_devops_enabled || 'hidden' }
- if @project.all_clusters.empty?
%p.settings-message.text-center
- - kubernetes_cluster_link = help_page_path('user/project/clusters/index')
- - kubernetes_cluster_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: kubernetes_cluster_link }
- = s_('CICD|You must add a %{kubernetes_cluster_start}Kubernetes cluster integration%{kubernetes_cluster_end} to this project with a domain in order for your deployment strategy to work correctly.').html_safe % { kubernetes_cluster_start: kubernetes_cluster_start, kubernetes_cluster_end: '</a>'.html_safe }
+ = s_('CICD|You must add a %{kubernetes_cluster_link_start}Kubernetes cluster integration%{link_end} to this project with a domain in order for your deployment strategy to work correctly.').html_safe % { kubernetes_cluster_link_start: kubernetes_cluster_link_start, link_end: link_end }
+ - elsif !has_base_domain
+ %p.settings-message.text-center
+ = s_('CICD|You must add a %{base_domain_link_start}base domain%{link_end} to your %{kubernetes_cluster_link_start}Kubernetes cluster%{link_end} in order for your deployment strategy to work.').html_safe % { base_domain_link_start: base_domain_link_start, kubernetes_cluster_link_start: kubernetes_cluster_link_start, link_end: link_end }
%label.prepend-top-10
%strong= s_('CICD|Deployment strategy')
.form-check
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index c87a084740b..b58af545439 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- breadcrumb_title _("Details")
- @content_class = "limit-container-width" unless fluid_layout
@@ -11,7 +10,7 @@
- signatures_path = project_signatures_path(@project, @project.default_branch)
.js-signature-container{ data: { 'signatures-path': signatures_path } }
-%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
+%div{ class: [("limit-container-width" unless fluid_layout)] }
= render "projects/last_push"
= render "home_panel"
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index 1f0de1e2603..6ad7cf1848f 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -1,10 +1,9 @@
-- @no_container = true
- @sort ||= sort_value_recently_updated
- page_title s_('TagsPage|Tags')
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_tags_url(@project, rss_url_options), title: "#{@project.name} tags")
-.flex-list{ class: container_class }
+.flex-list
.top-area.adjust
.nav-text.row-main-content
= s_('TagsPage|Tags give the ability to mark specific points in history as being important')
diff --git a/app/views/projects/tags/releases/edit.html.haml b/app/views/projects/tags/releases/edit.html.haml
index e4efeed04f0..40d886ff1af 100644
--- a/app/views/projects/tags/releases/edit.html.haml
+++ b/app/views/projects/tags/releases/edit.html.haml
@@ -1,22 +1,19 @@
-- @no_container = true
- add_to_breadcrumbs "Tags", project_tags_path(@project)
- breadcrumb_title @tag.name
- page_title "Edit", @tag.name, "Tags"
-%div{ class: container_class }
- .sub-header-block.no-bottom-space
- .oneline
- .title
- Release notes for tag
- %strong= @tag.name
+.sub-header-block.no-bottom-space
+ .oneline
+ .title
+ Release notes for tag
+ %strong= @tag.name
-
- = form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name),
- html: { class: 'common-note-form release-form js-quick-submit' }) do |f|
- = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
- = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here…"
- = render 'shared/notes/hints'
- .error-alert
- .prepend-top-default
- = f.submit 'Save changes', class: 'btn btn-success'
- = link_to "Cancel", project_tag_path(@project, @tag.name), class: "btn btn-default btn-cancel"
+= form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name),
+ html: { class: 'common-note-form release-form js-quick-submit' }) do |f|
+ = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
+ = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here…"
+ = render 'shared/notes/hints'
+ .error-alert
+ .prepend-top-default
+ = f.submit 'Save changes', class: 'btn btn-success'
+ = link_to "Cancel", project_tag_path(@project, @tag.name), class: "btn btn-default btn-cancel"
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index 78cce58938e..417cd7a8fee 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -1,45 +1,43 @@
-- @no_container = true
- add_to_breadcrumbs s_('TagsPage|Tags'), project_tags_path(@project)
- breadcrumb_title @tag.name
- page_title @tag.name, s_('TagsPage|Tags')
-%div{ class: container_class }
- .top-area.multi-line.flex-wrap
- .nav-text
- .title
- %span.item-title.ref-name
- = icon('tag')
- = @tag.name
- - if protected_tag?(@project, @tag)
- %span.badge.badge-success
- = s_('TagsPage|protected')
- - if @commit
- = render 'projects/branches/commit', commit: @commit, project: @project
- - else
- = s_("TagsPage|Can't find HEAD commit for this tag")
+.top-area.multi-line.flex-wrap
+ .nav-text
+ .title
+ %span.item-title.ref-name
+ = icon('tag')
+ = @tag.name
+ - if protected_tag?(@project, @tag)
+ %span.badge.badge-success
+ = s_('TagsPage|protected')
+ - if @commit
+ = render 'projects/branches/commit', commit: @commit, project: @project
+ - else
+ = s_("TagsPage|Can't find HEAD commit for this tag")
- .nav-controls
- - if can?(current_user, :admin_tag, @project)
- = link_to edit_project_tag_release_path(@project, @tag.name), class: 'btn btn-edit controls-item has-tooltip', title: s_('TagsPage|Edit release notes') do
- = icon("pencil")
- = link_to project_tree_path(@project, @tag.name), class: 'btn controls-item has-tooltip', title: s_('TagsPage|Browse files') do
- = sprite_icon('folder-open')
- = link_to project_commits_path(@project, @tag.name), class: 'btn controls-item has-tooltip', title: s_('TagsPage|Browse commits') do
- = icon('history')
- .btn-container.controls-item
- = render 'projects/buttons/download', project: @project, ref: @tag.name
- - if can?(current_user, :admin_tag, @project)
- .btn-container.controls-item-full
- = link_to project_tag_path(@project, @tag.name), class: "btn btn-remove remove-row has-tooltip #{protected_tag?(@project, @tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: @tag.name } } do
- %i.fa.fa-trash-o
+ .nav-controls
+ - if can?(current_user, :admin_tag, @project)
+ = link_to edit_project_tag_release_path(@project, @tag.name), class: 'btn btn-edit controls-item has-tooltip', title: s_('TagsPage|Edit release notes') do
+ = icon("pencil")
+ = link_to project_tree_path(@project, @tag.name), class: 'btn controls-item has-tooltip', title: s_('TagsPage|Browse files') do
+ = sprite_icon('folder-open')
+ = link_to project_commits_path(@project, @tag.name), class: 'btn controls-item has-tooltip', title: s_('TagsPage|Browse commits') do
+ = icon('history')
+ .btn-container.controls-item
+ = render 'projects/buttons/download', project: @project, ref: @tag.name
+ - if can?(current_user, :admin_tag, @project)
+ .btn-container.controls-item-full
+ = link_to project_tag_path(@project, @tag.name), class: "btn btn-remove remove-row has-tooltip #{protected_tag?(@project, @tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: @tag.name } } do
+ %i.fa.fa-trash-o
- - if @tag.message.present?
- %pre.wrap
- = strip_gpg_signature(@tag.message)
+ - if @tag.message.present?
+ %pre.wrap
+ = strip_gpg_signature(@tag.message)
- .append-bottom-default.prepend-top-default
- - if @release.description.present?
- .description.md
- = markdown_field(@release, :description)
- - else
- = s_('TagsPage|This tag has no release notes.')
+.append-bottom-default.prepend-top-default
+ - if @release.description.present?
+ .description.md
+ = markdown_field(@release, :description)
+ - else
+ = s_('TagsPage|This tag has no release notes.')
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index 9d2aee7a8bd..39b29a20df6 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -1,4 +1,3 @@
-- @no_container = true
- breadcrumb_title _("Repository")
- @content_class = "limit-container-width" unless fluid_layout
- signatures_path = namespace_project_signatures_path(namespace_id: @project.namespace.full_path, project_id: @project.path, id: @last_commit)
@@ -9,6 +8,5 @@
.js-signature-container{ data: { 'signatures-path': signatures_path } }
-%div{ class: [(container_class), ("limit-container-width" unless fluid_layout)] }
- = render 'projects/last_push'
- = render 'projects/files', commit: @last_commit, project: @project, ref: @ref, content_url: project_tree_path(@project, @id)
+= render 'projects/last_push'
+= render 'projects/files', commit: @last_commit, project: @project, ref: @ref, content_url: project_tree_path(@project, @id)
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
index 275dc5dbd23..d9dcd8f9acd 100644
--- a/app/views/projects/wikis/pages.html.haml
+++ b/app/views/projects/wikis/pages.html.haml
@@ -1,34 +1,32 @@
-- @no_container = true
- add_to_breadcrumbs "Wiki", project_wiki_path(@project, :home)
- breadcrumb_title s_("Wiki|Pages")
- page_title s_("Wiki|Pages"), _("Wiki")
- sort_title = wiki_sort_title(params[:sort])
-%div{ class: container_class }
- .wiki-page-header.top-area.flex-column.flex-lg-row
+.wiki-page-header.top-area.flex-column.flex-lg-row
- .nav-text.flex-fill
- %h2.wiki-page-title
- = s_("Wiki|Wiki Pages")
+ .nav-text.flex-fill
+ %h2.wiki-page-title
+ = s_("Wiki|Wiki Pages")
- .nav-controls.pb-md-3.pb-lg-0
- = link_to project_wikis_git_access_path(@project), class: 'btn' do
- = icon('cloud-download')
- = _("Clone repository")
+ .nav-controls.pb-md-3.pb-lg-0
+ = link_to project_wikis_git_access_path(@project), class: 'btn' do
+ = icon('cloud-download')
+ = _("Clone repository")
- .dropdown.inline.wiki-sort-dropdown
+ .dropdown.inline.wiki-sort-dropdown
+ .btn-group{ role: 'group' }
.btn-group{ role: 'group' }
- .btn-group{ role: 'group' }
- %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
- = sort_title
- = icon('chevron-down')
- %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
- %li
- = sortable_item(s_("Wiki|Title"), project_wikis_pages_path(@project, sort: ProjectWiki::TITLE_ORDER), sort_title)
- = sortable_item(s_("Wiki|Created date"), project_wikis_pages_path(@project, sort: ProjectWiki::CREATED_AT_ORDER), sort_title)
- = wiki_sort_controls(@project, params[:sort], params[:direction])
+ %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
+ = sort_title
+ = icon('chevron-down')
+ %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
+ %li
+ = sortable_item(s_("Wiki|Title"), project_wikis_pages_path(@project, sort: ProjectWiki::TITLE_ORDER), sort_title)
+ = sortable_item(s_("Wiki|Created date"), project_wikis_pages_path(@project, sort: ProjectWiki::CREATED_AT_ORDER), sort_title)
+ = wiki_sort_controls(@project, params[:sort], params[:direction])
- %ul.wiki-pages-list.content-list
- = render @wiki_entries, context: 'pages'
+%ul.wiki-pages-list.content-list
+ = render @wiki_entries, context: 'pages'
- = paginate @wiki_pages, theme: 'gitlab'
+= paginate @wiki_pages, theme: 'gitlab'
diff --git a/app/views/shared/empty_states/_priority_labels.html.haml b/app/views/shared/empty_states/_priority_labels.html.haml
index bba3475d244..a93f6e4c795 100644
--- a/app/views/shared/empty_states/_priority_labels.html.haml
+++ b/app/views/shared/empty_states/_priority_labels.html.haml
@@ -1,4 +1,6 @@
.text-center
.svg-content.qa-label-svg
= image_tag 'illustrations/priority_labels.svg'
- %p Star labels to start sorting by priority
+ - if can?(current_user, :admin_label, @project)
+ %p
+ = _("Star labels to start sorting by priority")
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 73bee7c2586..e1c75d5d0f4 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -1,9 +1,9 @@
- @hide_top_links = true
- @hide_breadcrumbs = true
+- @no_container = true
- page_title @user.name
- page_description @user.bio
- header_title @user.name, user_path(@user)
-- @no_container = true
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity")
diff --git a/app/workers/hashed_storage/base_worker.rb b/app/workers/hashed_storage/base_worker.rb
index 816e0504db6..237e278c537 100644
--- a/app/workers/hashed_storage/base_worker.rb
+++ b/app/workers/hashed_storage/base_worker.rb
@@ -5,7 +5,7 @@ module HashedStorage
include ExclusiveLeaseGuard
LEASE_TIMEOUT = 30.seconds.to_i
- LEASE_KEY_SEGMENT = 'project_migrate_hashed_storage_worker'.freeze
+ LEASE_KEY_SEGMENT = 'project_migrate_hashed_storage_worker'
protected
diff --git a/app/workers/stuck_ci_jobs_worker.rb b/app/workers/stuck_ci_jobs_worker.rb
index 30fba038937..7e002d8822c 100644
--- a/app/workers/stuck_ci_jobs_worker.rb
+++ b/app/workers/stuck_ci_jobs_worker.rb
@@ -4,7 +4,7 @@ class StuckCiJobsWorker
include ApplicationWorker
include CronjobQueue
- EXCLUSIVE_LEASE_KEY = 'stuck_ci_builds_worker_lease'.freeze
+ EXCLUSIVE_LEASE_KEY = 'stuck_ci_builds_worker_lease'
BUILD_RUNNING_OUTDATED_TIMEOUT = 1.hour
BUILD_PENDING_OUTDATED_TIMEOUT = 1.day
diff --git a/bin/rspec-stackprof b/bin/rspec-stackprof
index 810863ea4a0..8058d165196 100755
--- a/bin/rspec-stackprof
+++ b/bin/rspec-stackprof
@@ -3,7 +3,7 @@
require 'bundler/setup'
require 'stackprof'
$:.unshift 'spec'
-require 'rails_helper'
+require 'spec_helper'
filename = ARGV[0].split('/').last
interval = ENV.fetch('INTERVAL', 1000).to_i
diff --git a/changelogs/unreleased/36765-flash-notification.yml b/changelogs/unreleased/36765-flash-notification.yml
new file mode 100644
index 00000000000..3229cf6235a
--- /dev/null
+++ b/changelogs/unreleased/36765-flash-notification.yml
@@ -0,0 +1,5 @@
+---
+title: Make flash notifications sticky
+merge_request: 30141
+author:
+type: changed
diff --git a/changelogs/unreleased/40096-allow-ci-token-to-delete-from-registry.yml b/changelogs/unreleased/40096-allow-ci-token-to-delete-from-registry.yml
new file mode 100644
index 00000000000..3e5de08f6ae
--- /dev/null
+++ b/changelogs/unreleased/40096-allow-ci-token-to-delete-from-registry.yml
@@ -0,0 +1,5 @@
+---
+title: Allow $CI_REGISTRY_USER to delete tags
+merge_request: 31796
+author:
+type: added
diff --git a/changelogs/unreleased/51372-remove-milestone-tabs-deprecation-message.yml b/changelogs/unreleased/51372-remove-milestone-tabs-deprecation-message.yml
new file mode 100644
index 00000000000..5f05b150b93
--- /dev/null
+++ b/changelogs/unreleased/51372-remove-milestone-tabs-deprecation-message.yml
@@ -0,0 +1,5 @@
+---
+title: Remove deprecation message for milestone tabs
+merge_request: 32252
+author:
+type: other
diff --git a/changelogs/unreleased/60372-milestone-link-prevent-delete-issue-after-move-it-to-another-projec.yml b/changelogs/unreleased/60372-milestone-link-prevent-delete-issue-after-move-it-to-another-projec.yml
new file mode 100644
index 00000000000..d9f4c17a668
--- /dev/null
+++ b/changelogs/unreleased/60372-milestone-link-prevent-delete-issue-after-move-it-to-another-projec.yml
@@ -0,0 +1,5 @@
+---
+title: Add service to transfer Group Milestones when transferring a Project
+merge_request: 31778
+author:
+type: added
diff --git a/changelogs/unreleased/62402-milestone-release-be.yml b/changelogs/unreleased/62402-milestone-release-be.yml
new file mode 100644
index 00000000000..3b1f6edfe6b
--- /dev/null
+++ b/changelogs/unreleased/62402-milestone-release-be.yml
@@ -0,0 +1,5 @@
+---
+title: Allow milestones to be associated with a release (backend)
+merge_request: 30816
+author:
+type: added
diff --git a/changelogs/unreleased/62591-fix-milestone-due-date-today-wording.yml b/changelogs/unreleased/62591-fix-milestone-due-date-today-wording.yml
new file mode 100644
index 00000000000..532b582f407
--- /dev/null
+++ b/changelogs/unreleased/62591-fix-milestone-due-date-today-wording.yml
@@ -0,0 +1,5 @@
+---
+title: Fix wording on milestone due date when milestone is due today
+merge_request: 32096
+author:
+type: changed
diff --git a/changelogs/unreleased/64009-show-a-meaningful-error-message-when-due-quick_actions-command-fail.yml b/changelogs/unreleased/64009-show-a-meaningful-error-message-when-due-quick_actions-command-fail.yml
new file mode 100644
index 00000000000..8624b868686
--- /dev/null
+++ b/changelogs/unreleased/64009-show-a-meaningful-error-message-when-due-quick_actions-command-fail.yml
@@ -0,0 +1,5 @@
+---
+title: Show meaningful message on /due quick action with invalid date
+merge_request: 32349
+author: Jacopo Beschi @jacopo-beschi
+type: changed
diff --git a/changelogs/unreleased/66454-base-components.yml b/changelogs/unreleased/66454-base-components.yml
new file mode 100644
index 00000000000..7a40a66f122
--- /dev/null
+++ b/changelogs/unreleased/66454-base-components.yml
@@ -0,0 +1,5 @@
+---
+title: Creates base components for the new job log
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/66454-utils-parser.yml b/changelogs/unreleased/66454-utils-parser.yml
new file mode 100644
index 00000000000..80cd699937f
--- /dev/null
+++ b/changelogs/unreleased/66454-utils-parser.yml
@@ -0,0 +1,5 @@
+---
+title: Creates utility parser for the job log
+merge_request: 32555
+author:
+type: added
diff --git a/changelogs/unreleased/ab-add-index-for-ci-builds-metrics.yml b/changelogs/unreleased/ab-add-index-for-ci-builds-metrics.yml
new file mode 100644
index 00000000000..03a37dc0c04
--- /dev/null
+++ b/changelogs/unreleased/ab-add-index-for-ci-builds-metrics.yml
@@ -0,0 +1,5 @@
+---
+title: Create partial index for gitlab-monitor CI metrics
+merge_request: 32546
+author:
+type: performance
diff --git a/changelogs/unreleased/ab-remove-support-bot-column.yml b/changelogs/unreleased/ab-remove-support-bot-column.yml
new file mode 100644
index 00000000000..d256ded0410
--- /dev/null
+++ b/changelogs/unreleased/ab-remove-support-bot-column.yml
@@ -0,0 +1,5 @@
+---
+title: Remove Users.support_bot column
+merge_request: 32554
+author:
+type: other
diff --git a/changelogs/unreleased/ab-routable-nplus1.yml b/changelogs/unreleased/ab-routable-nplus1.yml
new file mode 100644
index 00000000000..7b59bc78dae
--- /dev/null
+++ b/changelogs/unreleased/ab-routable-nplus1.yml
@@ -0,0 +1,5 @@
+---
+title: Preload routes information to fix N+1 issue
+merge_request: 32352
+author:
+type: performance
diff --git a/changelogs/unreleased/ab-unconfirmed-email-index.yml b/changelogs/unreleased/ab-unconfirmed-email-index.yml
new file mode 100644
index 00000000000..3887cd87e41
--- /dev/null
+++ b/changelogs/unreleased/ab-unconfirmed-email-index.yml
@@ -0,0 +1,5 @@
+---
+title: Create index for users.unconfirmed_email
+merge_request: 32664
+author:
+type: performance
diff --git a/changelogs/unreleased/add-notification-reason-to-note-emails.yml b/changelogs/unreleased/add-notification-reason-to-note-emails.yml
new file mode 100644
index 00000000000..c27247b22cb
--- /dev/null
+++ b/changelogs/unreleased/add-notification-reason-to-note-emails.yml
@@ -0,0 +1,5 @@
+---
+title: Add X-GitLab-NotificationReason header to note emails
+merge_request: 32422
+author:
+type: fixed
diff --git a/changelogs/unreleased/change-prioritized-labels-empty-state-message.yml b/changelogs/unreleased/change-prioritized-labels-empty-state-message.yml
new file mode 100644
index 00000000000..d5df889d15c
--- /dev/null
+++ b/changelogs/unreleased/change-prioritized-labels-empty-state-message.yml
@@ -0,0 +1,5 @@
+---
+title: Change prioritized labels empty state message
+merge_request: 32338
+author: Lee Tickett
+type: other
diff --git a/changelogs/unreleased/change-role-system-hook.yml b/changelogs/unreleased/change-role-system-hook.yml
new file mode 100644
index 00000000000..adc9e43b1f2
--- /dev/null
+++ b/changelogs/unreleased/change-role-system-hook.yml
@@ -0,0 +1,5 @@
+---
+title: Add system hooks for project/group membership updates
+merge_request: 32371
+author: Brandon Williams
+type: added
diff --git a/changelogs/unreleased/cluster-form-ca-cert-larger.yml b/changelogs/unreleased/cluster-form-ca-cert-larger.yml
new file mode 100644
index 00000000000..ed38d003a37
--- /dev/null
+++ b/changelogs/unreleased/cluster-form-ca-cert-larger.yml
@@ -0,0 +1,5 @@
+---
+title: Expand textarea for CA cert in cluster form
+merge_request: 32508
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-regression-remove-installation-pod.yml b/changelogs/unreleased/fix-regression-remove-installation-pod.yml
new file mode 100644
index 00000000000..1ed72f1189d
--- /dev/null
+++ b/changelogs/unreleased/fix-regression-remove-installation-pod.yml
@@ -0,0 +1,5 @@
+---
+title: Fix removal of install pods
+merge_request: 32667
+author:
+type: fixed
diff --git a/changelogs/unreleased/fj-66723-add-dns-rebinding-protection-check.yml b/changelogs/unreleased/fj-66723-add-dns-rebinding-protection-check.yml
new file mode 100644
index 00000000000..c1372a4a73e
--- /dev/null
+++ b/changelogs/unreleased/fj-66723-add-dns-rebinding-protection-check.yml
@@ -0,0 +1,5 @@
+---
+title: Allow not resolvable urls when dns rebind protection is disabled
+merge_request: 32523
+author:
+type: fixed
diff --git a/changelogs/unreleased/fj-remove-dns-protection-when-validating.yml b/changelogs/unreleased/fj-remove-dns-protection-when-validating.yml
new file mode 100644
index 00000000000..9c74f8d69c7
--- /dev/null
+++ b/changelogs/unreleased/fj-remove-dns-protection-when-validating.yml
@@ -0,0 +1,5 @@
+---
+title: Avoid checking dns rebind protection when validating
+merge_request: 32577
+author:
+type: fixed
diff --git a/changelogs/unreleased/issue_54042.yml b/changelogs/unreleased/issue_54042.yml
new file mode 100644
index 00000000000..465c7426e93
--- /dev/null
+++ b/changelogs/unreleased/issue_54042.yml
@@ -0,0 +1,5 @@
+---
+title: Let project reporters create issue from group boards
+merge_request: 29866
+author:
+type: fixed
diff --git a/changelogs/unreleased/je-add-cluster-domain-warning.yml b/changelogs/unreleased/je-add-cluster-domain-warning.yml
new file mode 100644
index 00000000000..e7d244f730f
--- /dev/null
+++ b/changelogs/unreleased/je-add-cluster-domain-warning.yml
@@ -0,0 +1,5 @@
+---
+title: Add cluster domain warning
+merge_request: 32260
+author:
+type: changed
diff --git a/changelogs/unreleased/je-add-group-deployments-page-fe.yml b/changelogs/unreleased/je-add-group-deployments-page-fe.yml
new file mode 100644
index 00000000000..91333087eb5
--- /dev/null
+++ b/changelogs/unreleased/je-add-group-deployments-page-fe.yml
@@ -0,0 +1,5 @@
+---
+title: Add ability to see project deployments at cluster level (FE)
+merge_request: 31575
+author:
+type: added
diff --git a/changelogs/unreleased/persist-needs-error.yml b/changelogs/unreleased/persist-needs-error.yml
new file mode 100644
index 00000000000..96aaa4d11a3
--- /dev/null
+++ b/changelogs/unreleased/persist-needs-error.yml
@@ -0,0 +1,5 @@
+---
+title: Persist `needs:` validation as config error
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/remove-vue-resource-from-group-service.yml b/changelogs/unreleased/remove-vue-resource-from-group-service.yml
new file mode 100644
index 00000000000..771d301cabf
--- /dev/null
+++ b/changelogs/unreleased/remove-vue-resource-from-group-service.yml
@@ -0,0 +1,5 @@
+---
+title: Remove vue resource from group service
+merge_request:
+author: Lee Tickett
+type: other
diff --git a/changelogs/unreleased/remove-vue-resource-from-issue.yml b/changelogs/unreleased/remove-vue-resource-from-issue.yml
new file mode 100644
index 00000000000..b2de1b0913a
--- /dev/null
+++ b/changelogs/unreleased/remove-vue-resource-from-issue.yml
@@ -0,0 +1,5 @@
+---
+title: Remove vue resource from issue
+merge_request: 32421
+author: Lee Tickett
+type: other
diff --git a/changelogs/unreleased/sh-suppress-diverging-count-commits-request.yml b/changelogs/unreleased/sh-suppress-diverging-count-commits-request.yml
new file mode 100644
index 00000000000..68b95ff9318
--- /dev/null
+++ b/changelogs/unreleased/sh-suppress-diverging-count-commits-request.yml
@@ -0,0 +1,5 @@
+---
+title: Skip requesting diverging commit counts if no branches are listed
+merge_request: 32496
+author:
+type: performance
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 20b1020e025..e3693f612e3 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -158,6 +158,7 @@ production: &base
# The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
# The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`).
+ # Please be aware that a placeholder is required for the Service Desk feature to work.
address: "gitlab-incoming+%{key}@gmail.com"
# Email account username
@@ -431,6 +432,7 @@ production: &base
# key: config/registry.key
# path: shared/registry
# issuer: gitlab-issuer
+ # notification_secret: '' # only set it when you use Geo replication feature without built-in Registry
# Add notification settings if you plan to use Geo Replication for the registry
# notifications:
diff --git a/config/routes.rb b/config/routes.rb
index c333550f758..02a405a91f8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -67,7 +67,7 @@ Rails.application.routes.draw do
get 'health_check(/:checks)' => 'health_check#index', as: :health_check
scope path: '-' do
- # '/-/health' implemented by BasicHealthMiddleware
+ # '/-/health' implemented by BasicHealthCheck middleware
get 'liveness' => 'health#liveness'
get 'readiness' => 'health#readiness'
resources :metrics, only: [:index]
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index ea165508d29..7edec576f9a 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -102,6 +102,7 @@
- [create_github_webhook, 2]
- [geo, 1]
- [repository_update_mirror, 1]
+ - [repository_push_audit_event, 1]
- [new_epic, 2]
- [project_import_schedule, 1]
- [project_update_repository_storage, 1]
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index 78ceb74da65..9d293f425e6 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -18,6 +18,7 @@ class Gitlab::Seeder::CycleAnalytics
# Milestones / Labels
Timecop.travel 5.days.from_now
+
if index.even?
issue_metrics.first_associated_with_milestone_at = rand(6..12).hours.from_now
else
@@ -146,7 +147,7 @@ class Gitlab::Seeder::CycleAnalytics
commit_sha = issue.project.repository.create_file(@user, filename, "content", message: "Commit for #{issue.to_reference}", branch_name: branch_name)
issue.project.repository.commit(commit_sha)
- Git::BranchPushService.new(
+ ::Git::BranchPushService.new(
issue.project,
@user,
oldrev: issue.project.repository.commit("master").sha,
@@ -182,7 +183,8 @@ class Gitlab::Seeder::CycleAnalytics
ref: "refs/heads/#{merge_request.source_branch}")
pipeline = service.execute(:push, ignore_skip_ci: true, save_on_errors: false)
- pipeline.builds.map(&:run!)
+ pipeline.builds.each(&:enqueue) # make sure all pipelines in pending state
+ pipeline.builds.each(&:run!)
pipeline.update_status
end
end
diff --git a/db/migrate/20190722144316_create_milestone_releases_table.rb b/db/migrate/20190722144316_create_milestone_releases_table.rb
new file mode 100644
index 00000000000..55878bcec41
--- /dev/null
+++ b/db/migrate/20190722144316_create_milestone_releases_table.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class CreateMilestoneReleasesTable < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ create_table :milestone_releases do |t|
+ t.references :milestone, foreign_key: { on_delete: :cascade }, null: false, index: false
+ t.references :release, foreign_key: { on_delete: :cascade }, null: false
+ end
+
+ add_index :milestone_releases, [:milestone_id, :release_id], unique: true, name: 'index_miletone_releases_on_milestone_and_release'
+ end
+
+ def down
+ drop_table :milestone_releases
+ end
+end
diff --git a/db/migrate/20190826100605_add_group_column_to_events.rb b/db/migrate/20190826100605_add_group_column_to_events.rb
new file mode 100644
index 00000000000..cd7b2b1d96a
--- /dev/null
+++ b/db/migrate/20190826100605_add_group_column_to_events.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddGroupColumnToEvents < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_reference :events, :group, index: true, foreign_key: { to_table: :namespaces, on_delete: :cascade }
+ end
+end
diff --git a/db/migrate/20190828110802_add_not_null_constraints_to_prometheus_metrics_y_label_and_unit.rb b/db/migrate/20190828110802_add_not_null_constraints_to_prometheus_metrics_y_label_and_unit.rb
new file mode 100644
index 00000000000..6f3650ca966
--- /dev/null
+++ b/db/migrate/20190828110802_add_not_null_constraints_to_prometheus_metrics_y_label_and_unit.rb
@@ -0,0 +1,8 @@
+class AddNotNullConstraintsToPrometheusMetricsYLabelAndUnit < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ change_column_null(:prometheus_metrics, :y_label, false)
+ change_column_null(:prometheus_metrics, :unit, false)
+ end
+end
diff --git a/db/migrate/20190902152329_add_index_for_ci_builds_metrics.rb b/db/migrate/20190902152329_add_index_for_ci_builds_metrics.rb
new file mode 100644
index 00000000000..b755d60e311
--- /dev/null
+++ b/db/migrate/20190902152329_add_index_for_ci_builds_metrics.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddIndexForCiBuildsMetrics < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'ci_builds_gitlab_monitor_metrics'
+
+ def up
+ add_concurrent_index(:ci_builds, [:status, :created_at, :project_id], where: "type = 'Ci::Build'", name: INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_index_by_name(:ci_builds, INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20190904173203_add_index_on_users_unconfirmed_email.rb b/db/migrate/20190904173203_add_index_on_users_unconfirmed_email.rb
new file mode 100644
index 00000000000..e78d47f023f
--- /dev/null
+++ b/db/migrate/20190904173203_add_index_on_users_unconfirmed_email.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexOnUsersUnconfirmedEmail < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :users, :unconfirmed_email, where: 'unconfirmed_email IS NOT NULL'
+ end
+
+ def down
+ remove_concurrent_index :users, :unconfirmed_email, where: 'unconfirmed_email IS NOT NULL'
+ end
+end
diff --git a/db/post_migrate/20190902160015_remove_support_bot_column_from_users.rb b/db/post_migrate/20190902160015_remove_support_bot_column_from_users.rb
new file mode 100644
index 00000000000..80d69b57f5d
--- /dev/null
+++ b/db/post_migrate/20190902160015_remove_support_bot_column_from_users.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class RemoveSupportBotColumnFromUsers < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ return unless column_exists?(:users, :support_bot)
+
+ remove_column :users, :support_bot
+ end
+
+ def down
+ # no-op because the column should not exist in the previous version
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 5b89cdf0b98..98c4403efe1 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2019_09_02_131045) do
+ActiveRecord::Schema.define(version: 2019_09_04_173203) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -605,6 +605,7 @@ ActiveRecord::Schema.define(version: 2019_09_02_131045) do
t.index ["scheduled_at"], name: "partial_index_ci_builds_on_scheduled_at_with_scheduled_jobs", where: "((scheduled_at IS NOT NULL) AND ((type)::text = 'Ci::Build'::text) AND ((status)::text = 'scheduled'::text))"
t.index ["stage_id", "stage_idx"], name: "tmp_build_stage_position_index", where: "(stage_idx IS NOT NULL)"
t.index ["stage_id"], name: "index_ci_builds_on_stage_id"
+ t.index ["status", "created_at", "project_id"], name: "ci_builds_gitlab_monitor_metrics", where: "((type)::text = 'Ci::Build'::text)"
t.index ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id"
t.index ["token"], name: "index_ci_builds_on_token", unique: true
t.index ["token_encrypted"], name: "index_ci_builds_on_token_encrypted", unique: true, where: "(token_encrypted IS NOT NULL)"
@@ -1310,9 +1311,11 @@ ActiveRecord::Schema.define(version: 2019_09_02_131045) do
t.datetime_with_timezone "updated_at", null: false
t.integer "action", limit: 2, null: false
t.string "target_type"
+ t.bigint "group_id"
t.index ["action"], name: "index_events_on_action"
t.index ["author_id", "project_id"], name: "index_events_on_author_id_and_project_id"
t.index ["created_at", "author_id"], name: "analytics_index_events_on_created_at_and_author_id"
+ t.index ["group_id"], name: "index_events_on_group_id"
t.index ["project_id", "created_at"], name: "index_events_on_project_id_and_created_at"
t.index ["project_id", "id"], name: "index_events_on_project_id_and_id"
t.index ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id"
@@ -2158,6 +2161,13 @@ ActiveRecord::Schema.define(version: 2019_09_02_131045) do
t.index ["user_id"], name: "index_merge_trains_on_user_id"
end
+ create_table "milestone_releases", force: :cascade do |t|
+ t.bigint "milestone_id", null: false
+ t.bigint "release_id", null: false
+ t.index ["milestone_id", "release_id"], name: "index_miletone_releases_on_milestone_and_release", unique: true
+ t.index ["release_id"], name: "index_milestone_releases_on_release_id"
+ end
+
create_table "milestones", id: :serial, force: :cascade do |t|
t.string "title", null: false
t.integer "project_id"
@@ -2869,8 +2879,8 @@ ActiveRecord::Schema.define(version: 2019_09_02_131045) do
t.integer "project_id"
t.string "title", null: false
t.string "query", null: false
- t.string "y_label"
- t.string "unit"
+ t.string "y_label", null: false
+ t.string "unit", null: false
t.string "legend"
t.integer "group", null: false
t.datetime_with_timezone "created_at", null: false
@@ -3553,6 +3563,7 @@ ActiveRecord::Schema.define(version: 2019_09_02_131045) do
t.index ["state"], name: "index_users_on_state"
t.index ["state"], name: "index_users_on_state_and_internal", where: "(ghost IS NOT TRUE)"
t.index ["state"], name: "index_users_on_state_and_internal_ee", where: "((ghost IS NOT TRUE) AND (bot_type IS NULL))"
+ t.index ["unconfirmed_email"], name: "index_users_on_unconfirmed_email", where: "(unconfirmed_email IS NOT NULL)"
t.index ["username"], name: "index_users_on_username"
t.index ["username"], name: "index_users_on_username_trigram", opclass: :gin_trgm_ops, using: :gin
end
@@ -3831,6 +3842,7 @@ ActiveRecord::Schema.define(version: 2019_09_02_131045) do
add_foreign_key "epics", "users", column: "assignee_id", name: "fk_dccd3f98fc", on_delete: :nullify
add_foreign_key "epics", "users", column: "author_id", name: "fk_3654b61b03", on_delete: :cascade
add_foreign_key "epics", "users", column: "closed_by_id", name: "fk_aa5798e761", on_delete: :nullify
+ add_foreign_key "events", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "events", "projects", on_delete: :cascade
add_foreign_key "events", "users", column: "author_id", name: "fk_edfd187b6f", on_delete: :cascade
add_foreign_key "fork_network_members", "fork_networks", on_delete: :cascade
@@ -3932,6 +3944,8 @@ ActiveRecord::Schema.define(version: 2019_09_02_131045) do
add_foreign_key "merge_trains", "merge_requests", on_delete: :cascade
add_foreign_key "merge_trains", "projects", column: "target_project_id", on_delete: :cascade
add_foreign_key "merge_trains", "users", on_delete: :cascade
+ add_foreign_key "milestone_releases", "milestones", on_delete: :cascade
+ add_foreign_key "milestone_releases", "releases", on_delete: :cascade
add_foreign_key "milestones", "namespaces", column: "group_id", name: "fk_95650a40d4", on_delete: :cascade
add_foreign_key "milestones", "projects", name: "fk_9bd0a0c791", on_delete: :cascade
add_foreign_key "namespace_aggregation_schedules", "namespaces", on_delete: :cascade
diff --git a/doc/README.md b/doc/README.md
index 9a0252cc334..c704bedc7d6 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -357,9 +357,10 @@ The following documentation relates to the DevOps **Secure** stage:
| [Dependency List](user/application_security/dependency_list/index.md) **(ULTIMATE)** | View your project's dependencies and their known vulnerabilities. |
| [Dependency Scanning](user/application_security/dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
| [Dynamic Application Security Testing (DAST)](user/application_security/dast/index.md) **(ULTIMATE)** | Analyze running web applications for known vulnerabilities. |
-| [Group Security Dashboard](user/application_security/security_dashboard/index.md) **(ULTIMATE)** | View vulnerabilities in all the projects in a group and its subgroups. |
+| [Group Security Dashboard](user/application_security/security_dashboard/index.md#group-security-dashboard) **(ULTIMATE)** | View vulnerabilities in all the projects in a group and its subgroups. |
| [License Compliance](user/application_security/license_compliance/index.md) **(ULTIMATE)** | Search your project's dependencies for their licenses. |
-| [Project Security Dashboard](user/application_security/security_dashboard/index.md) **(ULTIMATE)** | View the latest security reports for your project. |
+| [Pipeline Security Dashboard](user/application_security/security_dashboard/index.md#pipeline-security-dashboard) **(ULTIMATE)** | View the security reports for your project's pipelines. |
+| [Project Security Dashboard](user/application_security/security_dashboard/index.md#project-security-dashboard) **(ULTIMATE)** | View the latest security reports for your project. |
| [Static Application Security Testing (SAST)](user/application_security/sast/index.md) **(ULTIMATE)** | Analyze source code for known vulnerabilities. |
## New to Git and GitLab?
diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md
index 407539885a6..7228cc6948e 100644
--- a/doc/administration/geo/disaster_recovery/index.md
+++ b/doc/administration/geo/disaster_recovery/index.md
@@ -315,7 +315,7 @@ section to resolve the error. Otherwise, the secret is lost and you'll need to
[geo-limitations]: ../replication/index.md#current-limitations
[planned-failover]: planned_failover.md
[setup-geo]: ../replication/index.md#setup-instructions
-[updating-geo]: ../replication/updating_the_geo_nodes.md#upgrading-to-gitlab-105
+[updating-geo]: ../replication/version_specific_updates.md#updating-to-gitlab-105
[sec-tfa]: ../../../security/two_factor_authentication.md#disabling-2fa-for-everyone
[gitlab-org/omnibus-gitlab#3058]: https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3058
[gitlab-org/gitlab-ee#4284]: https://gitlab.com/gitlab-org/gitlab-ee/issues/4284
diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md
index 8c27c4dac4f..fda0ebbbeac 100644
--- a/doc/administration/geo/replication/updating_the_geo_nodes.md
+++ b/doc/administration/geo/replication/updating_the_geo_nodes.md
@@ -1,6 +1,26 @@
# Updating the Geo nodes **(PREMIUM ONLY)**
-Depending on which version of Geo you are updating to/from, there may be different steps.
+Updating Geo nodes involves performing:
+
+1. [Version-specific update steps](#version-specific-update-steps), depending on the
+ version being updated to or from.
+1. [General update steps](#general-update-steps), for all updates.
+
+## Version specific update steps
+
+Depending on which version of Geo you are updating to/from, there may be
+different steps.
+
+- [Updating to GitLab 12.1](version_specific_updates.md#updating-to-gitlab-121)
+- [Updating to GitLab 10.8](version_specific_updates.md#updating-to-gitlab-108)
+- [Updating to GitLab 10.6](version_specific_updates.md#updating-to-gitlab-106)
+- [Updating to GitLab 10.5](version_specific_updates.md#updating-to-gitlab-105)
+- [Updating to GitLab 10.3](version_specific_updates.md#updating-to-gitlab-103)
+- [Updating to GitLab 10.2](version_specific_updates.md#updating-to-gitlab-102)
+- [Updating to GitLab 10.1](version_specific_updates.md#updating-to-gitlab-101)
+- [Updating to GitLab 10.0](version_specific_updates.md#updating-to-gitlab-100)
+- [Updating from GitLab 9.3 or older](version_specific_updates.md#updating-from-gitlab-93-or-older)
+- [Updating to GitLab 9.0](version_specific_updates.md#updating-to-gitlab-90)
## General update steps
@@ -31,428 +51,3 @@ everything is working correctly:
is received by **secondary** nodes.
If you encounter any issues, please consult the [Geo troubleshooting guide](troubleshooting.md).
-
-## Upgrading to GitLab 12.1
-
-By default, GitLab 12.1 will attempt to automatically upgrade the embedded PostgreSQL server to 10.7 from 9.6. Please see [the omnibus documentation](https://docs.gitlab.com/omnibus/settings/database.html#upgrading-a-geo-instance) for the recommended procedure.
-
-This can be temporarily disabled by running the following before ugprading:
-
-```sh
-sudo touch /etc/gitlab/disable-postgresql-upgrade
-```
-
-## Upgrading to GitLab 10.8
-
-Before 10.8, broadcast messages would not propagate without flushing the cache on the **secondary** nodes. This has been fixed in 10.8, but requires one last cache flush on each **secondary** node:
-
-```sh
-sudo gitlab-rake cache:clear
-```
-
-## Upgrading to GitLab 10.6
-
-In 10.4, we started to recommend that you define a password for database user (`gitlab`).
-
-We now require this change as we use this password to enable the Foreign Data Wrapper, as a way to optimize
-the Geo Tracking Database. We are also improving security by disabling the use of **trust**
-authentication method.
-
-1. **(primary)** Login to your **primary** node and run:
-
- ```sh
- gitlab-ctl pg-password-md5 gitlab
- # Enter password: <your_password_here>
- # Confirm password: <your_password_here>
- # fca0b89a972d69f00eb3ec98a5838484
- ```
-
- Copy the generated hash and edit `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
- postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
-
- # Every node that runs Unicorn or Sidekiq needs to have the database
- # password specified as below. If you have a high-availability setup, this
- # must be present in all application nodes.
- gitlab_rails['db_password'] = '<your_password_here>'
- ```
-
- Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
-
- ```ruby
- postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','1.2.3.4/32'] # <- Remove this
- ```
-
-1. **(primary)** Reconfigure and restart:
-
- ```sh
- sudo gitlab-ctl reconfigure
- sudo gitlab-ctl restart
- ```
-
-1. **(secondary)** Login to all **secondary** nodes and edit `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
- postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
-
- # Every node that runs Unicorn or Sidekiq needs to have the database
- # password specified as below. If you have a high-availability setup, this
- # must be present in all application nodes.
- gitlab_rails['db_password'] = '<your_password_here>'
-
- # Enable Foreign Data Wrapper
- geo_secondary['db_fdw'] = true
-
- # Secondary address in CIDR format, for example '5.6.7.8/32'
- postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32']
- ```
-
- Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
-
- ```ruby
- postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','5.6.7.8/32'] # <- Remove this
- ```
-
-1. **(secondary)** Reconfigure and restart:
-
- ```sh
- sudo gitlab-ctl reconfigure
- sudo gitlab-ctl restart
- ```
-
-## Upgrading to GitLab 10.5
-
-For Geo Disaster Recovery to work with minimum downtime, your **secondary** node
-should use the same set of secrets as the **primary** node. However, setup instructions
-prior to the 10.5 release only synchronized the `db_key_base` secret.
-
-To rectify this error on existing installations, you should **overwrite** the
-contents of `/etc/gitlab/gitlab-secrets.json` on each **secondary** node with the
-contents of `/etc/gitlab/gitlab-secrets.json` on the **primary** node, then run the
-following command on each **secondary** node:
-
-```sh
-sudo gitlab-ctl reconfigure
-```
-
-If you do not perform this step, you may find that two-factor authentication
-[is broken following DR](../disaster_recovery/index.html#i-followed-the-disaster-recovery-instructions-and-now-two-factor-auth-is-broken).
-
-To prevent SSH requests to the newly promoted **primary** node from failing
-due to SSH host key mismatch when updating the **primary** node domain's DNS record
-you should perform the step to [Manually replicate **primary** SSH host keys](configuration.md#step-2-manually-replicate-the-primary-nodes-ssh-host-keys) in each
-**secondary** node.
-
-## Upgrading to GitLab 10.4
-
-There are no Geo-specific steps to take!
-
-## Upgrading to GitLab 10.3
-
-### Support for SSH repository synchronization removed
-
-In GitLab 10.2, synchronizing secondaries over SSH was deprecated. In 10.3,
-support is removed entirely. All installations will switch to the HTTP/HTTPS
-cloning method instead. Before upgrading, ensure that all your Geo nodes are
-configured to use this method and that it works for your installation. In
-particular, ensure that [Git access over HTTP/HTTPS is enabled](configuration.md#step-6-enable-git-access-over-httphttps).
-
-Synchronizing repositories over the public Internet using HTTP is insecure, so
-you should ensure that you have HTTPS configured before upgrading. Note that
-file synchronization is **also** insecure in these cases!
-
-## Upgrading to GitLab 10.2
-
-### Secure PostgreSQL replication
-
-Support for TLS-secured PostgreSQL replication has been added. If you are
-currently using PostgreSQL replication across the open internet without an
-external means of securing the connection (e.g., a site-to-site VPN), then you
-should immediately reconfigure your **primary** and **secondary** PostgreSQL instances
-according to the [updated instructions][database].
-
-If you *are* securing the connections externally and wish to continue doing so,
-ensure you include the new option `--sslmode=prefer` in future invocations of
-`gitlab-ctl replicate-geo-database`.
-
-### HTTPS repository sync
-
-Support for replicating repositories and wikis over HTTP/HTTPS has been added.
-Replicating over SSH has been deprecated, and support for this option will be
-removed in a future release.
-
-To switch to HTTP/HTTPS replication, log into the **primary** node as an admin and visit
-**Admin Area > Geo** (`/admin/geo/nodes`). For each **secondary** node listed,
-press the "Edit" button, change the "Repository cloning" setting from
-"SSH (deprecated)" to "HTTP/HTTPS", and press "Save changes". This should take
-effect immediately.
-
-Any new secondaries should be created using HTTP/HTTPS replication - this is the
-default setting.
-
-After you've verified that HTTP/HTTPS replication is working, you should remove
-the now-unused SSH keys from your secondaries, as they may cause problems if the
-**secondary** node if ever promoted to a **primary** node:
-
-1. **(secondary)** Login to **all** your **secondary** nodes and run:
-
- ```ruby
- sudo -u git -H rm ~git/.ssh/id_rsa ~git/.ssh/id_rsa.pub
- ```
-
-### Hashed Storage
-
-CAUTION: **Warning:**
-Hashed storage is in **Alpha**. It is considered experimental and not
-production-ready. See [Hashed Storage] for more detail.
-
-If you previously enabled Hashed Storage and migrated all your existing
-projects to Hashed Storage, disabling hashed storage will not migrate projects
-to their previous project based storage path. As such, once enabled and
-migrated we recommend leaving Hashed Storage enabled.
-
-## Upgrading to GitLab 10.1
-
-CAUTION: **Warning:**
-Hashed storage is in **Alpha**. It is considered experimental and not
-production-ready. See [Hashed Storage] for more detail.
-
-[Hashed storage] was introduced in GitLab 10.0, and a [migration path][hashed-migration]
-for existing repositories was added in GitLab 10.1.
-
-## Upgrading to GitLab 10.0
-
-Since GitLab 10.0, we require all **Geo** systems to [use SSH key lookups via
-the database][ssh-fast-lookup] to avoid having to maintain consistency of the
-`authorized_keys` file for SSH access. Failing to do this will prevent users
-from being able to clone via SSH.
-
-Note that in older versions of Geo, attachments downloaded on the **secondary**
-nodes would be saved to the wrong directory. We recommend that you do the
-following to clean this up.
-
-On the **secondary** Geo nodes, run as root:
-
-```sh
-mv /var/opt/gitlab/gitlab-rails/working /var/opt/gitlab/gitlab-rails/working.old
-mkdir /var/opt/gitlab/gitlab-rails/working
-chmod 700 /var/opt/gitlab/gitlab-rails/working
-chown git:git /var/opt/gitlab/gitlab-rails/working
-```
-
-You may delete `/var/opt/gitlab/gitlab-rails/working.old` any time.
-
-Once this is done, we advise restarting GitLab on the **secondary** nodes for the
-new working directory to be used:
-
-```sh
-sudo gitlab-ctl restart
-```
-
-## Upgrading from GitLab 9.3 or older
-
-If you started running Geo on GitLab 9.3 or older, we recommend that you
-resync your **secondary** PostgreSQL databases to use replication slots. If you
-started using Geo with GitLab 9.4 or 10.x, no further action should be
-required because replication slots are used by default. However, if you
-started with GitLab 9.3 and upgraded later, you should still follow the
-instructions below.
-
-When in doubt, it does not hurt to do a resync. The easiest way to do this in
-Omnibus is the following:
-
-1. Make sure you have Omnibus GitLab on the **primary** server.
-1. Run `gitlab-ctl reconfigure` and `gitlab-ctl restart postgresql`. This will enable replication slots on the **primary** database.
-1. Check the steps about defining `postgresql['sql_user_password']`, `gitlab_rails['db_password']`.
-1. Make sure `postgresql['max_replication_slots']` matches the number of **secondary** Geo nodes locations.
-1. Install GitLab on the **secondary** server.
-1. Re-run the [database replication process](database.md#step-3-initiate-the-replication-process).
-
-## Special update notes for 9.0.x
-
-> **IMPORTANT**:
-With GitLab 9.0, the PostgreSQL version is upgraded to 9.6 and manual steps are
-required in order to update the **secondary** nodes and keep the Streaming
-Replication working. Downtime is required, so plan ahead.
-
-The following steps apply only if you upgrade from a 8.17 GitLab version to
-9.0+. For previous versions, update to GitLab 8.17 first before attempting to
-upgrade to 9.0+.
-
----
-
-Make sure to follow the steps in the exact order as they appear below and pay
-extra attention in what node (either **primary** or **secondary**) you execute them! Each step
-is prepended with the relevant node for better clarity:
-
-1. **(secondary)** Login to **all** your **secondary** nodes and stop all services:
-
- ```ruby
- sudo gitlab-ctl stop
- ```
-
-1. **(secondary)** Make a backup of the `recovery.conf` file on **all**
- **secondary** nodes to preserve PostgreSQL's credentials:
-
- ```sh
- sudo cp /var/opt/gitlab/postgresql/data/recovery.conf /var/opt/gitlab/
- ```
-
-1. **(primary)** Update the **primary** node to GitLab 9.0 following the
- [regular update docs][update]. At the end of the update, the **primary** node
- will be running with PostgreSQL 9.6.
-
-1. **(primary)** To prevent a de-synchronization of the repository replication,
- stop all services except `postgresql` as we will use it to re-initialize the
- **secondary** node's database:
-
- ```sh
- sudo gitlab-ctl stop
- sudo gitlab-ctl start postgresql
- ```
-
-1. **(secondary)** Run the following steps on each of the **secondary** nodes:
-
- 1. **(secondary)** Stop all services:
-
- ```sh
- sudo gitlab-ctl stop
- ```
-
- 1. **(secondary)** Prevent running database migrations:
-
- ```sh
- sudo touch /etc/gitlab/skip-auto-migrations
- ```
-
- 1. **(secondary)** Move the old database to another directory:
-
- ```sh
- sudo mv /var/opt/gitlab/postgresql{,.bak}
- ```
-
- 1. **(secondary)** Update to GitLab 9.0 following the [regular update docs][update].
- At the end of the update, the node will be running with PostgreSQL 9.6.
-
- 1. **(secondary)** Make sure all services are up:
-
- ```sh
- sudo gitlab-ctl start
- ```
-
- 1. **(secondary)** Reconfigure GitLab:
-
- ```sh
- sudo gitlab-ctl reconfigure
- ```
-
- 1. **(secondary)** Run the PostgreSQL upgrade command:
-
- ```sh
- sudo gitlab-ctl pg-upgrade
- ```
-
- 1. **(secondary)** See the stored credentials for the database that you will
- need to re-initialize the replication:
-
- ```sh
- sudo grep -s primary_conninfo /var/opt/gitlab/recovery.conf
- ```
-
- 1. **(secondary)** Save the snippet below in a file, let's say `/tmp/replica.sh`. Modify the
- embedded paths if necessary:
-
- ```
- #!/bin/bash
-
- PORT="5432"
- USER="gitlab_replicator"
- echo ---------------------------------------------------------------
- echo WARNING: Make sure this script is run from the secondary server
- echo ---------------------------------------------------------------
- echo
- echo Enter the IP or FQDN of the primary PostgreSQL server
- read HOST
- echo Enter the password for $USER@$HOST
- read -s PASSWORD
- echo Enter the required sslmode
- read SSLMODE
-
- echo Stopping PostgreSQL and all GitLab services
- sudo service gitlab stop
- sudo service postgresql stop
-
- echo Backing up postgresql.conf
- sudo -u postgres mv /var/opt/gitlab/postgresql/data/postgresql.conf /var/opt/gitlab/postgresql/
-
- echo Cleaning up old cluster directory
- sudo -u postgres rm -rf /var/opt/gitlab/postgresql/data
-
- echo Starting base backup as the replicator user
- echo Enter the password for $USER@$HOST
- sudo -u postgres /opt/gitlab/embedded/bin/pg_basebackup -h $HOST -D /var/opt/gitlab/postgresql/data -U gitlab_replicator -v -x -P
-
- echo Writing recovery.conf file
- sudo -u postgres bash -c "cat > /var/opt/gitlab/postgresql/data/recovery.conf <<- _EOF1_
- standby_mode = 'on'
- primary_conninfo = 'host=$HOST port=$PORT user=$USER password=$PASSWORD sslmode=$SSLMODE'
- _EOF1_
- "
-
- echo Restoring postgresql.conf
- sudo -u postgres mv /var/opt/gitlab/postgresql/postgresql.conf /var/opt/gitlab/postgresql/data/
-
- echo Starting PostgreSQL
- sudo service postgresql start
- ```
-
- 1. **(secondary)** Run the recovery script using the credentials from the
- previous step:
-
- ```sh
- sudo bash /tmp/replica.sh
- ```
-
- 1. **(secondary)** Reconfigure GitLab:
-
- ```sh
- sudo gitlab-ctl reconfigure
- ```
-
- 1. **(secondary)** Start all services:
-
- ```sh
- sudo gitlab-ctl start
- ```
-
- 1. **(secondary)** Repeat the steps for the remaining **secondary** nodes.
-
-1. **(primary)** After all **secondary** nodes are updated, start all services in
- **primary** node:
-
- ```sh
- sudo gitlab-ctl start
- ```
-
-### Update tracking database on **secondary** node
-
-After updating a **secondary** node, you might need to run migrations on
-the tracking database. The tracking database was added in GitLab 9.1,
-and it is required since 10.0.
-
-1. Run database migrations on tracking database:
-
- ```sh
- sudo gitlab-rake geo:db:migrate
- ```
-
-1. Repeat this step for each **secondary** node.
-
-[update]: ../../../update/README.md
-[database]: database.md
-[Hashed Storage]: ../../repository_storage_types.md
-[hashed-migration]: ../../raketasks/storage.md
-[ssh-fast-lookup]: ../../operations/fast_ssh_key_lookup.md
diff --git a/doc/administration/geo/replication/version_specific_updates.md b/doc/administration/geo/replication/version_specific_updates.md
new file mode 100644
index 00000000000..6d550a49df4
--- /dev/null
+++ b/doc/administration/geo/replication/version_specific_updates.md
@@ -0,0 +1,426 @@
+# Version specific update instructions
+
+Check this document if it includes instructions for the version you are updating.
+These steps go together with the [general steps](updating_the_geo_nodes.md#general-update-steps)
+for updating Geo nodes.
+
+## Updating to GitLab 12.1
+
+By default, GitLab 12.1 will attempt to automatically update the
+embedded PostgreSQL server to 10.7 from 9.6. Please see
+[the omnibus documentation](https://docs.gitlab.com/omnibus/settings/database.html#upgrading-a-geo-instance)
+for the recommended procedure.
+
+This can be temporarily disabled by running the following before updating:
+
+```sh
+sudo touch /etc/gitlab/disable-postgresql-upgrade
+```
+
+## Updating to GitLab 10.8
+
+Before 10.8, broadcast messages would not propagate without flushing
+the cache on the **secondary** nodes. This has been fixed in 10.8, but
+requires one last cache flush on each **secondary** node:
+
+```sh
+sudo gitlab-rake cache:clear
+```
+
+## Updating to GitLab 10.6
+
+In 10.4, we started to recommend that you define a password for database user (`gitlab`).
+
+We now require this change as we use this password to enable the Foreign Data Wrapper, as a way to optimize
+the Geo Tracking Database. We are also improving security by disabling the use of **trust**
+authentication method.
+
+1. **(primary)** Login to your **primary** node and run:
+
+ ```sh
+ gitlab-ctl pg-password-md5 gitlab
+ # Enter password: <your_password_here>
+ # Confirm password: <your_password_here>
+ # fca0b89a972d69f00eb3ec98a5838484
+ ```
+
+ Copy the generated hash and edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
+ postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
+
+ # Every node that runs Unicorn or Sidekiq needs to have the database
+ # password specified as below. If you have a high-availability setup, this
+ # must be present in all application nodes.
+ gitlab_rails['db_password'] = '<your_password_here>'
+ ```
+
+ Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
+
+ ```ruby
+ postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','1.2.3.4/32'] # <- Remove this
+ ```
+
+1. **(primary)** Reconfigure and restart:
+
+ ```sh
+ sudo gitlab-ctl reconfigure
+ sudo gitlab-ctl restart
+ ```
+
+1. **(secondary)** Login to all **secondary** nodes and edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
+ postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
+
+ # Every node that runs Unicorn or Sidekiq needs to have the database
+ # password specified as below. If you have a high-availability setup, this
+ # must be present in all application nodes.
+ gitlab_rails['db_password'] = '<your_password_here>'
+
+ # Enable Foreign Data Wrapper
+ geo_secondary['db_fdw'] = true
+
+ # Secondary address in CIDR format, for example '5.6.7.8/32'
+ postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32']
+ ```
+
+ Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
+
+ ```ruby
+ postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','5.6.7.8/32'] # <- Remove this
+ ```
+
+1. **(secondary)** Reconfigure and restart:
+
+ ```sh
+ sudo gitlab-ctl reconfigure
+ sudo gitlab-ctl restart
+ ```
+
+## Updating to GitLab 10.5
+
+For Geo Disaster Recovery to work with minimum downtime, your **secondary** node
+should use the same set of secrets as the **primary** node. However, setup instructions
+prior to the 10.5 release only synchronized the `db_key_base` secret.
+
+To rectify this error on existing installations, you should **overwrite** the
+contents of `/etc/gitlab/gitlab-secrets.json` on each **secondary** node with the
+contents of `/etc/gitlab/gitlab-secrets.json` on the **primary** node, then run the
+following command on each **secondary** node:
+
+```sh
+sudo gitlab-ctl reconfigure
+```
+
+If you do not perform this step, you may find that two-factor authentication
+[is broken following DR](../disaster_recovery/index.html#i-followed-the-disaster-recovery-instructions-and-now-two-factor-auth-is-broken).
+
+To prevent SSH requests to the newly promoted **primary** node from failing
+due to SSH host key mismatch when updating the **primary** node domain's DNS record
+you should perform the step to [Manually replicate **primary** SSH host keys](configuration.md#step-2-manually-replicate-the-primary-nodes-ssh-host-keys) in each
+**secondary** node.
+
+## Updating to GitLab 10.3
+
+### Support for SSH repository synchronization removed
+
+In GitLab 10.2, synchronizing secondaries over SSH was deprecated. In 10.3,
+support is removed entirely. All installations will switch to the HTTP/HTTPS
+cloning method instead. Before updating, ensure that all your Geo nodes are
+configured to use this method and that it works for your installation. In
+particular, ensure that [Git access over HTTP/HTTPS is enabled](configuration.md#step-6-enable-git-access-over-httphttps).
+
+Synchronizing repositories over the public Internet using HTTP is insecure, so
+you should ensure that you have HTTPS configured before updating. Note that
+file synchronization is **also** insecure in these cases!
+
+## Updating to GitLab 10.2
+
+### Secure PostgreSQL replication
+
+Support for TLS-secured PostgreSQL replication has been added. If you are
+currently using PostgreSQL replication across the open internet without an
+external means of securing the connection (e.g., a site-to-site VPN), then you
+should immediately reconfigure your **primary** and **secondary** PostgreSQL instances
+according to the [updated instructions](database.md).
+
+If you *are* securing the connections externally and wish to continue doing so,
+ensure you include the new option `--sslmode=prefer` in future invocations of
+`gitlab-ctl replicate-geo-database`.
+
+### HTTPS repository sync
+
+Support for replicating repositories and wikis over HTTP/HTTPS has been added.
+Replicating over SSH has been deprecated, and support for this option will be
+removed in a future release.
+
+To switch to HTTP/HTTPS replication, log into the **primary** node as an admin and visit
+**Admin Area > Geo** (`/admin/geo/nodes`). For each **secondary** node listed,
+press the "Edit" button, change the "Repository cloning" setting from
+"SSH (deprecated)" to "HTTP/HTTPS", and press "Save changes". This should take
+effect immediately.
+
+Any new secondaries should be created using HTTP/HTTPS replication - this is the
+default setting.
+
+After you've verified that HTTP/HTTPS replication is working, you should remove
+the now-unused SSH keys from your secondaries, as they may cause problems if the
+**secondary** node if ever promoted to a **primary** node:
+
+1. **(secondary)** Login to **all** your **secondary** nodes and run:
+
+ ```ruby
+ sudo -u git -H rm ~git/.ssh/id_rsa ~git/.ssh/id_rsa.pub
+ ```
+
+### Hashed Storage
+
+CAUTION: **Warning:**
+Hashed storage is in **Alpha**. It is considered experimental and not
+production-ready. See [Hashed Storage](../../repository_storage_types.md) for more detail.
+
+If you previously enabled Hashed Storage and migrated all your existing
+projects to Hashed Storage, disabling hashed storage will not migrate projects
+to their previous project based storage path. As such, once enabled and
+migrated we recommend leaving Hashed Storage enabled.
+
+## Updating to GitLab 10.1
+
+CAUTION: **Warning:**
+Hashed storage is in **Alpha**. It is considered experimental and not
+production-ready. See [Hashed Storage](../../repository_storage_types.md) for more detail.
+
+[Hashed storage](../../repository_storage_types.md) was introduced in
+GitLab 10.0, and a [migration path](../../raketasks/storage.md) for
+existing repositories was added in GitLab 10.1.
+
+## Updating to GitLab 10.0
+
+Since GitLab 10.0, we require all **Geo** systems to [use SSH key lookups via
+the database](../../operations/fast_ssh_key_lookup.md) to avoid having to maintain consistency of the
+`authorized_keys` file for SSH access. Failing to do this will prevent users
+from being able to clone via SSH.
+
+Note that in older versions of Geo, attachments downloaded on the **secondary**
+nodes would be saved to the wrong directory. We recommend that you do the
+following to clean this up.
+
+On the **secondary** Geo nodes, run as root:
+
+```sh
+mv /var/opt/gitlab/gitlab-rails/working /var/opt/gitlab/gitlab-rails/working.old
+mkdir /var/opt/gitlab/gitlab-rails/working
+chmod 700 /var/opt/gitlab/gitlab-rails/working
+chown git:git /var/opt/gitlab/gitlab-rails/working
+```
+
+You may delete `/var/opt/gitlab/gitlab-rails/working.old` any time.
+
+Once this is done, we advise restarting GitLab on the **secondary** nodes for the
+new working directory to be used:
+
+```sh
+sudo gitlab-ctl restart
+```
+
+## Updating from GitLab 9.3 or older
+
+If you started running Geo on GitLab 9.3 or older, we recommend that you
+resync your **secondary** PostgreSQL databases to use replication slots. If you
+started using Geo with GitLab 9.4 or 10.x, no further action should be
+required because replication slots are used by default. However, if you
+started with GitLab 9.3 and updated later, you should still follow the
+instructions below.
+
+When in doubt, it does not hurt to do a resync. The easiest way to do this in
+Omnibus is the following:
+
+1. Make sure you have Omnibus GitLab on the **primary** server.
+1. Run `gitlab-ctl reconfigure` and `gitlab-ctl restart postgresql`. This will enable replication slots on the **primary** database.
+1. Check the steps about defining `postgresql['sql_user_password']`, `gitlab_rails['db_password']`.
+1. Make sure `postgresql['max_replication_slots']` matches the number of **secondary** Geo nodes locations.
+1. Install GitLab on the **secondary** server.
+1. Re-run the [database replication process](database.md#step-3-initiate-the-replication-process).
+
+## Updating to GitLab 9.0
+
+> **IMPORTANT**:
+With GitLab 9.0, the PostgreSQL version is updated to 9.6 and manual steps are
+required in order to update the **secondary** nodes and keep the Streaming
+Replication working. Downtime is required, so plan ahead.
+
+The following steps apply only if you update from a 8.17 GitLab version to
+9.0+. For previous versions, update to GitLab 8.17 first before attempting to
+update to 9.0+.
+
+---
+
+Make sure to follow the steps in the exact order as they appear below and pay
+extra attention in what node (either **primary** or **secondary**) you execute them! Each step
+is prepended with the relevant node for better clarity:
+
+1. **(secondary)** Log in to **all** your **secondary** nodes and stop all services:
+
+ ```ruby
+ sudo gitlab-ctl stop
+ ```
+
+1. **(secondary)** Make a backup of the `recovery.conf` file on **all**
+ **secondary** nodes to preserve PostgreSQL's credentials:
+
+ ```sh
+ sudo cp /var/opt/gitlab/postgresql/data/recovery.conf /var/opt/gitlab/
+ ```
+
+1. **(primary)** Update the **primary** node to GitLab 9.0 following the
+ [regular update docs](../../../update/README.md). At the end of the
+ update, the **primary** node will be running with PostgreSQL 9.6.
+
+1. **(primary)** To prevent a de-synchronization of the repository replication,
+ stop all services except `postgresql` as we will use it to re-initialize the
+ **secondary** node's database:
+
+ ```sh
+ sudo gitlab-ctl stop
+ sudo gitlab-ctl start postgresql
+ ```
+
+1. **(secondary)** Run the following steps on each of the **secondary** nodes:
+
+ 1. **(secondary)** Stop all services:
+
+ ```sh
+ sudo gitlab-ctl stop
+ ```
+
+ 1. **(secondary)** Prevent running database migrations:
+
+ ```sh
+ sudo touch /etc/gitlab/skip-auto-migrations
+ ```
+
+ 1. **(secondary)** Move the old database to another directory:
+
+ ```sh
+ sudo mv /var/opt/gitlab/postgresql{,.bak}
+ ```
+
+ 1. **(secondary)** Update to GitLab 9.0 following the [regular update docs](../../../update/README.md).
+ At the end of the update, the node will be running with PostgreSQL 9.6.
+
+ 1. **(secondary)** Make sure all services are up:
+
+ ```sh
+ sudo gitlab-ctl start
+ ```
+
+ 1. **(secondary)** Reconfigure GitLab:
+
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
+
+ 1. **(secondary)** Run the PostgreSQL upgrade command:
+
+ ```sh
+ sudo gitlab-ctl pg-upgrade
+ ```
+
+ 1. **(secondary)** See the stored credentials for the database that you will
+ need to re-initialize the replication:
+
+ ```sh
+ sudo grep -s primary_conninfo /var/opt/gitlab/recovery.conf
+ ```
+
+ 1. **(secondary)** Save the snippet below in a file, let's say `/tmp/replica.sh`. Modify the
+ embedded paths if necessary:
+
+ ```
+ #!/bin/bash
+
+ PORT="5432"
+ USER="gitlab_replicator"
+ echo ---------------------------------------------------------------
+ echo WARNING: Make sure this script is run from the secondary server
+ echo ---------------------------------------------------------------
+ echo
+ echo Enter the IP or FQDN of the primary PostgreSQL server
+ read HOST
+ echo Enter the password for $USER@$HOST
+ read -s PASSWORD
+ echo Enter the required sslmode
+ read SSLMODE
+
+ echo Stopping PostgreSQL and all GitLab services
+ sudo service gitlab stop
+ sudo service postgresql stop
+
+ echo Backing up postgresql.conf
+ sudo -u postgres mv /var/opt/gitlab/postgresql/data/postgresql.conf /var/opt/gitlab/postgresql/
+
+ echo Cleaning up old cluster directory
+ sudo -u postgres rm -rf /var/opt/gitlab/postgresql/data
+
+ echo Starting base backup as the replicator user
+ echo Enter the password for $USER@$HOST
+ sudo -u postgres /opt/gitlab/embedded/bin/pg_basebackup -h $HOST -D /var/opt/gitlab/postgresql/data -U gitlab_replicator -v -x -P
+
+ echo Writing recovery.conf file
+ sudo -u postgres bash -c "cat > /var/opt/gitlab/postgresql/data/recovery.conf <<- _EOF1_
+ standby_mode = 'on'
+ primary_conninfo = 'host=$HOST port=$PORT user=$USER password=$PASSWORD sslmode=$SSLMODE'
+ _EOF1_
+ "
+
+ echo Restoring postgresql.conf
+ sudo -u postgres mv /var/opt/gitlab/postgresql/postgresql.conf /var/opt/gitlab/postgresql/data/
+
+ echo Starting PostgreSQL
+ sudo service postgresql start
+ ```
+
+ 1. **(secondary)** Run the recovery script using the credentials from the
+ previous step:
+
+ ```sh
+ sudo bash /tmp/replica.sh
+ ```
+
+ 1. **(secondary)** Reconfigure GitLab:
+
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
+
+ 1. **(secondary)** Start all services:
+
+ ```sh
+ sudo gitlab-ctl start
+ ```
+
+ 1. **(secondary)** Repeat the steps for the remaining **secondary** nodes.
+
+1. **(primary)** After all **secondary** nodes are updated, start all services in
+ **primary** node:
+
+ ```sh
+ sudo gitlab-ctl start
+ ```
+
+### Update tracking database on **secondary** node
+
+After updating a **secondary** node, you might need to run migrations on
+the tracking database. The tracking database was added in GitLab 9.1,
+and it is required since 10.0.
+
+1. Run database migrations on tracking database:
+
+ ```sh
+ sudo gitlab-rake geo:db:migrate
+ ```
+
+1. Repeat this step for each **secondary** node.
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index eab4b2c6eea..53b354d2f92 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -148,7 +148,7 @@ Check the directory layout on your Gitaly server to be sure.
<!--
updates to following example must also be made at
- https://gitlab.com/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
+ https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
-->
```ruby
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 650cb10a64a..d557068e6c8 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -139,6 +139,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Repository checks](repository_checks.md): Periodic Git repository checks.
- [Repository storage paths](repository_storage_paths.md): Manage the paths used to store repositories.
+- [Repository storage types](repository_storage_types.md): Information about the different repository storage types.
- [Repository storage rake tasks](raketasks/storage.md): A collection of rake tasks to list and migrate existing projects and attachments associated with it from Legacy storage to Hashed storage.
- [Limit repository size](../user/admin_area/settings/account_and_limit_settings.md): Set a hard limit for your repositories' size. **(STARTER ONLY)**
@@ -186,13 +187,29 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Debugging tips](troubleshooting/debug.md): Tips to debug problems when things go wrong
- [Log system](logs.md): Where to look for logs.
- [Sidekiq Troubleshooting](troubleshooting/sidekiq.md): Debug when Sidekiq appears hung and is not processing jobs.
-- Useful [diagnostics tools](troubleshooting/diagnostics_tools.md) that are sometimes used by the GitLab
- Support team.
-- [Troubleshooting ElasticSearch](troubleshooting/elasticsearch.md): Tips to troubleshoot ElasticSearch.
-- [Kubernetes troubleshooting](troubleshooting/kubernetes_cheat_sheet.md): Commands and tips useful
- for troubleshooting Kubernetes-related issues.
-- Useful links from the Support Team:
- - [GitLab Developer Docs](https://docs.gitlab.com/ee/development/README.html).
- - [Repairing and recovering broken Git repositories](https://git.seveas.net/repairing-and-recovering-broken-git-repositories.html).
- - [Testing with OpenSSL](https://www.feistyduck.com/library/openssl-cookbook/online/ch-testing-with-openssl.html).
- - [Strace zine](https://wizardzines.com/zines/strace/).
+- [Troubleshooting ElasticSearch](troubleshooting/elasticsearch.md)
+
+### Support Team Docs
+
+The GitLab Support Team has collected a lot of information about troubleshooting GitLab
+instances. These documents are normally used by the Support Team itself, or by customers
+with direct guidance from a Support Team member. GitLab administrators may find the
+information useful for troubleshooting, but if you are experiencing trouble with your
+GitLab instance, you should check your [support options](https://about.gitlab.com/support/)
+before referring to these documents.
+
+CAUTION: **Warning:**
+Using the commands listed in the documentation below could result in data loss or
+other damage to a GitLab instance, and should only be used by experienced administrators
+who are aware of the risks.
+
+- [Useful diagnostics tools](troubleshooting/diagnostics_tools.md)
+- [Useful Linux commands](troubleshooting/linux_cheat_sheet.md)
+- [Troubleshooting Kubernetes](troubleshooting/kubernetes_cheat_sheet.md)
+- [Guide to test environments](troubleshooting/test_environments.md) (for Support Engineers)
+- [GitLab rails console commands](troubleshooting/gitlab_rails_cheat_sheet.md) (for Support Engineers)
+- Useful links:
+ - [GitLab Developer Docs](../development/README.md)
+ - [Repairing and recovering broken Git repositories](https://git.seveas.net/repairing-and-recovering-broken-git-repositories.html)
+ - [Testing with OpenSSL](https://www.feistyduck.com/library/openssl-cookbook/online/ch-testing-with-openssl.html)
+ - [Strace zine](https://wizardzines.com/zines/strace/)
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 9b1efb610f8..4c43a434817 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -341,9 +341,10 @@ installations from source.
## `database_load_balancing.log`
-Introduced in GitLab 12.3 for observability of [Database Load
-Balancing](https://docs.gitlab.com/ee/administration/database_load_balancing.html)
-when enabled. This file lives in
-`/var/log/gitlab/gitlab-rails/database_load_balancing.log` for Omnibus GitLab
-packages or in `/home/git/gitlab/log/database_load_balancing.log` for
-installations from source.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15442) in GitLab 12.3.
+
+This log is used for observability of [Database Load Balancing](database_load_balancing.md).
+It is stored at:
+
+- `/var/log/gitlab/gitlab-rails/database_load_balancing.log` for Omnibus GitLab packages.
+- `/home/git/gitlab/log/database_load_balancing.log` for installations from source.
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
new file mode 100644
index 00000000000..0c5611aa6cd
--- /dev/null
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -0,0 +1,1040 @@
+---
+type: reference
+---
+
+# GitLab Rails Console Cheat Sheet
+
+This is the GitLab Support Team's collection of information regarding the GitLab rails
+console, for use while troubleshooting. It is listed here for transparency,
+and it may be useful for users with experience with these tools. If you are currently
+having an issue with GitLab, it is highly recommended that you check your
+[support options](https://about.gitlab.com/support/) first, before attempting to use
+this information.
+
+CAUTION: **CAUTION:**
+Please note that some of these scripts could be damaging if not run correctly,
+or under the right conditions. We highly recommend running them under the
+guidance of a Support Engineer, or running them in a test environment with a
+backup of the instance ready to be restored, just in case.
+
+CAUTION: **CAUTION:**
+Please also note that as GitLab changes, changes to the code are inevitable,
+and so some scripts may not work as they once used to. These are not kept
+up-to-date as these scripts/commands were added as they were found/needed. As
+mentioned above, we recommend running these scripts under the supervision of a
+Support Engineer, who can also verify that they will continue to work as they
+should and, if needed, update the script for the latest version of GitLab.
+
+## Use the Rails Runner
+
+If the script you want to run is short, you can use the Rails Runner to avoid
+entering the rails console in the first place. Here's an example of its use:
+
+```bash
+gitlab-rails runner "RAILS_COMMAND"
+
+# Example with a 2-line script
+gitlab-rails runner "user = User.first; puts user.username"
+```
+
+## Enable debug logging on rails console
+
+```ruby
+Rails.logger.level = 0
+```
+
+## Enable debug logging for ActiveRecord (db issues)
+
+```ruby
+ActiveRecord::Base.logger = Logger.new(STDOUT)
+```
+
+## Temporarily Disable Timeout
+
+```ruby
+ActiveRecord::Base.connection.execute('SET statement_timeout TO 0')
+```
+
+## Find specific methods for an object
+
+```ruby
+Array.methods.select { |m| m.to_s.include? "sing" }
+Array.methods.grep(/sing/)
+```
+
+## Find method source
+
+Works for [non-instrumented methods](https://docs.gitlab.com/ce/development/instrumentation.html#checking-instrumented-methods):
+
+```ruby
+instance_of_object.method(:foo).source_location
+
+# Example for when we would call project.private?
+project.method(:private?).source_location
+```
+
+## Query an object
+
+```ruby
+o = Object.where('attribute like ?', 'ex')
+```
+
+## View all keys in cache
+
+```ruby
+Rails.cache.instance_variable_get(:@data).keys
+```
+
+## Rails console history
+
+```ruby
+puts Readline::HISTORY.to_a
+```
+
+## Profile a page
+
+```ruby
+# Before 11.6.0
+logger = Logger.new(STDOUT)
+admin_token = User.find_by_username('ADMIN_USERNAME').personal_access_tokens.first.token
+app.get("URL/?private_token=#{admin_token}")
+
+# From 11.6.0
+admin = User.find_by_username('ADMIN_USERNAME')
+url = "/url/goes/here"
+Gitlab::Profiler.with_user(admin) { app.get(url) }
+```
+
+## Using the GitLab profiler inside console (used as of 10.5)
+
+```ruby
+logger = Logger.new(STDOUT)
+admin = User.find_by_username('ADMIN_USERNAME')
+Gitlab::Profiler.profile('URL', logger: logger, user: admin)
+```
+
+## Time an operation
+
+```ruby
+# A single operation
+Benchmark.measure { <operation> }
+
+# A breakdown of multiple operations
+Benchmark.bm do |x|
+ x.report(:label1) { <operation_1> }
+ x.report(:label2) { <operation_2> }
+end
+```
+
+## Command Line
+
+### Check the GitLab version fast
+
+```bash
+grep -m 1 gitlab /opt/gitlab/version-manifest.txt
+```
+
+### Debugging SSH
+
+```bash
+GIT_SSH_COMMAND="ssh -vvv" git clone <repository>
+```
+
+### Debugging over HTTPS
+
+```bash
+GIT_CURL_VERBOSE=1 GIT_TRACE=1 git clone <repository>
+```
+
+## Projects
+
+### Find projects
+
+```ruby
+# A single project
+project = Project.find_by_full_path('PROJECT_PATH')
+
+# All projects in a particular namespace. Can be a username, a group
+# ('gitlab-org'), or even include subgroups ('gitlab-org/distribution')
+namespace = Namespace.find_by_full_path('NAMESPACE_PATH')
+projects = namespace.all_projects
+```
+
+### Clear a project's cache
+
+```ruby
+ProjectCacheWorker.perform_async(project.id)
+```
+
+### Expire the .exists? cache
+
+```ruby
+project.repository.expire_exists_cache
+```
+
+### Make all projects private
+
+```ruby
+Project.update_all(visibility_level: 0)
+```
+
+### Find & remove projects that are pending deletion
+
+```ruby
+#
+# This section will list all the projects which are pending deletion
+#
+projects = Project.where(pending_delete: true)
+projects.each do |p|
+ puts "Project name: #{p.id}"
+ puts "Project name: #{p.name}"
+ puts "Repository path: #{p.repository.storage_path}"
+end
+
+#
+# Assign a user (the root user will do)
+#
+user = User.find_by_username('root')
+
+#
+# For each project listed repeat these two commands
+#
+
+# Find the project, update the xxx-changeme values from above
+project = Project.find_by_full_path('group-changeme/project-changeme')
+
+# Delete the project
+::Projects::DestroyService.new(project, user, {}).execute
+```
+
+Next, run `sudo gitlab-rake gitlab:cleanup:repos` on the command line to finish.
+
+### Destroy a project
+
+```ruby
+project = Project.find_by_full_path('')
+user = User.find_by_username('')
+ProjectDestroyWorker.perform_async(project.id, user.id, {})
+# or ProjectDestroyWorker.new.perform(project.id, user.id, {})
+# or Projects::DestroyService.new(project, user).execute
+```
+
+### Remove fork relationship manually
+
+```ruby
+p = Project.find_by_full_path('')
+u = User.find_by_username('')
+::Projects::UnlinkForkService.new(p, u).execute
+```
+
+### Make a project read-only (can only be done in the console)
+
+```ruby
+# Make a project read-only
+project.repository_read_only = true; project.save
+
+# OR
+project.update!(repository_read_only: true)
+```
+
+### Bulk update service integration password for _all_ projects
+
+For example, change the Jira user's password for all projects that have the Jira
+integration active:
+
+```ruby
+p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN services s ON p.id = s.project_id WHERE s.type = 'JiraService' AND s.active = true")
+
+p.each do |project|
+ project.jira_service.update_attribute(:password, '<your-new-password>')
+end
+```
+
+### Identify un-indexed projects
+
+```ruby
+Project.find_each do |project|
+ puts "id #{project.id}: #{project.namespace.name.to_s}/#{project.name.to_s}" if project.index_status.nil?
+end
+```
+
+## Imports / Exports
+
+```ruby
+# Find the project and get the error
+p = Project.find_by_full_path('<username-or-group>/<project-name>')
+
+p.import_error
+
+# To finish the import on GitLab running version before 11.6
+p.import_finish
+
+# To finish the import on GitLab running version 11.6 or after
+p.import_state.mark_as_failed("Failed manually through console.")
+```
+
+### Rename imported repository
+
+In a specific situation, an imported repository needed to be renamed. The Support
+Team was informed of a backup restore that failed on a single repository, which created
+the project with an empty repository. The project was successfully restored to a dev
+instance, then exported, and imported into a new project under a different name.
+
+The Support Team was able to transfer the incorrectly named imported project into the
+correctly named empty project using the steps below.
+
+Move the new repository to the empty repository:
+
+```bash
+mv /var/opt/gitlab/git-data/repositories/<group>/<new-project> /var/opt/gitlab/git-data/repositories/<group>/<empty-project>
+```
+
+Make sure the permissions are correct:
+
+```bash
+chown -R git:git <path-to-directory>.git
+```
+
+Clear the cache:
+
+```bash
+sudo gitlab-rake cache:clear
+```
+
+## Repository
+
+### Search sequence of pushes to a repository
+
+If it seems that a commit has gone "missing", search the sequence of pushes to a repository.
+[This StackOverflow article](https://stackoverflow.com/questions/13468027/the-mystery-of-the-missing-commit-across-merges)
+describes how you can end up in this state without a force push.
+
+If you look at the output from the sample code below for the target branch, you will
+see a discontinuity in the from/to commits as you step through the output. Each new
+push should be "from" the "to" SHA of the previous push. When this discontinuity happens,
+you will see two pushes with the same "from" SHA:
+
+```ruby
+p = Project.find_with_namespace('u/p')
+p.events.code_push.last(100).each do |e|
+ printf "%-20.20s %8s...%8s (%s)\n", e.data[:ref], e.data[:before], e.data[:after], e.author.try(:username)
+end
+```
+
+GitLab 9.5 and above:
+
+```ruby
+p = Project.find_by_full_path('u/p')
+p.events.code_push.last(100).each do |e|
+ printf "%-20.20s %8s...%8s (%s)\n", e.push_event_payload[:ref], e.push_event_payload[:commit_from], e.push_event_payload[:commit_to], e.author.try(:username)
+end
+```
+
+## Mirrors
+
+### Find mirrors with "bad decrypt" errors
+
+```ruby
+total = 0
+bad = []
+ProjectImportData.find_each do |data|
+ begin
+ total += 1
+ data.credentials
+ rescue => e
+ bad << data
+ end
+end
+
+puts "Bad count: #{bad.count} / #{total}"
+bad.each do |repo|
+ puts Project.find(repo.project_id).full_path
+end; bad.count
+```
+
+### Transfer mirror users and tokens to a single service account
+
+Use case: If you have multiple users using their own GitHub credentials to set up
+repository mirroring, mirroring breaks when people leave the company. Use this
+script to migrate disparate mirroring users and tokens into a single service account:
+
+```ruby
+svc_user = User.find_by(username: 'ourServiceUser')
+token = 'githubAccessToken'
+
+Project.where(mirror: true).each do |project|
+ import_url = project.import_url
+
+ # The url we want is https://token@project/path.git
+ repo_url = if import_url.include?('@')
+ # Case 1: The url is something like https://23423432@project/path.git
+ import_url.split('@').last
+ elsif import_url.include?('//')
+ # Case 2: The url is something like https://project/path.git
+ import_url.split('//').last
+ end
+
+ next unless repo_url
+
+ final_url = "https://#{token}@#{repo_url}"
+
+ project.mirror_user = svc_user
+ project.import_url = final_url
+ project.username_only_import_url = final_url
+ project.save
+end
+```
+
+## Users
+
+### Finding users
+
+```ruby
+# By username
+user = User.find_by(username: '')
+
+# By primary email
+user = User.find_by(email: '')
+
+# By any email (primary or secondary)
+user = User.find_by_any_email('')
+
+# Admins
+User.admins
+admin = User.admins.first
+```
+
+### Block
+
+```ruby
+User.find_by_username().block!
+```
+
+### Unblock
+
+```ruby
+User.find_by_username().active
+```
+
+### Skip reconfirmation
+
+```ruby
+user = User.find_by_username ''
+user.skip_reconfirmation!
+```
+
+### Get an admin token
+
+```ruby
+# Get the first admin's first access token (no longer works on 11.9+. see: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22743)
+User.where(admin:true).first.personal_access_tokens.first.token
+
+# Get the first admin's private token (no longer works on 10.2+)
+User.where(admin:true).private_token
+```
+
+### Create personal access token
+
+```ruby
+personal_access_token = User.find(123).personal_access_tokens.create(
+ name: 'apitoken',
+ impersonation: false,
+ scopes: [:api]
+)
+
+personal_access_token.token
+```
+
+You might also want to manually set the token string:
+
+```ruby
+User.find(123).personal_access_tokens.create(
+ name: 'apitoken',
+ token_digest: Gitlab::CryptoHelper.sha256('some-token-string-here'),
+ impersonation: false,
+ scopes: [:api]
+)
+```
+
+### Disable 2FA on a user
+
+```ruby
+user = User.find_by_username('username')
+user.disable_two_factor!
+```
+
+### Active users & Historical users
+
+```ruby
+# Active users on the instance, now
+User.active.count
+
+# The historical max on the instance as of the past year
+::HistoricalData.max_historical_user_count
+```
+
+```bash
+# Using curl and jq (up to a max 100, see [pagination](https://docs.gitlab.com/ee/api/#pagination)
+curl --silent --header "Private-Token: ********************" "https://gitlab.example.com/api/v4/users?per_page=100&active" | jq --compact-output '.[] | [.id,.name,.username]'
+```
+
+### Block or Delete Users that have no projects or groups
+
+```ruby
+users = User.where('id NOT IN (select distinct(user_id) from project_authorizations)')
+
+# How many users will be removed?
+users.count
+
+# If that count looks sane:
+
+# You can either block the users:
+users.each { |user| user.block! }
+
+# Or you can delete them:
+ # need 'current user' (your user) for auditing purposes
+current_user = User.find_by(username: '<your username>')
+
+users.each do |user|
+ DeleteUserWorker.perform_async(current_user.id, user.id)
+end
+```
+
+### Block Users that have no recent activity
+
+```ruby
+days_inactive = 60
+inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
+
+inactive_users.each do |user|
+ puts "user '#{user.username}': #{user.last_activity_on}"
+ user.block!
+end
+```
+
+### Find Max permissions for project/group
+
+```ruby
+user = User.find_by_username 'username'
+project = Project.find_by_full_path 'group/project'
+user.max_member_access_for_project project.id
+```
+
+```ruby
+user = User.find_by_username 'username'
+group = Group.find_by_full_path 'group'
+user.max_member_access_for_group group.id
+```
+
+## Groups
+
+### Count unique users in a group and sub-groups
+
+```ruby
+group = Group.find_by_path_or_name("groupname")
+members = []
+for member in group.members_with_descendants
+ members.push(member.user_name)
+end
+
+members.uniq.length
+```
+
+```ruby
+group = Group.find_by_path_or_name("groupname")
+
+# Count users from subgroup and up (inherited)
+group.members_with_parents.count
+
+# Count users from parent group and down (specific grants)
+parent.members_with_descendants.count
+```
+
+### Delete a group
+
+```ruby
+GroupDestroyWorker.perform_async(group_id, user_id)
+```
+
+## LDAP
+
+### LDAP commands in the rails console
+
+TIP: **TIP:**
+Use the rails runner to avoid entering the rails console in the first place.
+This is great when only a single command (such as a UserSync or GroupSync)
+is needed.
+
+```ruby
+# Get debug output
+Rails.logger.level = Logger::DEBUG
+
+# Run a UserSync (normally performed once a day)
+LdapSyncWorker.new.perform
+
+# Run a GroupSync for all groups (9.3-)
+LdapGroupSyncWorker.new.perform
+
+# Run a GroupSync for all groups (9.3+)
+LdapAllGroupsSyncWorker.new.perform
+
+# Run a GroupSync for a single group (10.6-)
+group = Group.find_by(name: 'my_gitlab_group')
+EE::Gitlab::LDAP::Sync::Group.execute_all_providers(group)
+
+# Run a GroupSync for a single group (10.6+)
+group = Group.find_by(name: 'my_gitlab_group')
+EE::Gitlab::Auth::LDAP::Sync::Group.execute_all_providers(group)
+
+# Query an LDAP group directly (10.6-)
+adapter = Gitlab::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider
+ldap_group = EE::Gitlab::LDAP::Group.find_by_cn('group_cn_here', adapter)
+ldap_group.member_dns
+ldap_group.member_uids
+
+# Query an LDAP group directly (10.6+)
+adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider
+ldap_group = EE::Gitlab::Auth::LDAP::Group.find_by_cn('group_cn_here', adapter)
+ldap_group.member_dns
+ldap_group.member_uids
+
+# Lookup a particular user (10.6+)
+# This could expose potential errors connecting to and/or querying LDAP that may seem to
+# fail silently in the GitLab UI
+adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider
+user = Gitlab::Auth::LDAP::Person.find_by_uid('<username>',adapter)
+
+# Query the LDAP server directly (10.6+)
+## For an example, see https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/lib/ee/gitlab/auth/ldap/adapter.rb
+adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain')
+options = {
+ # the :base is required
+ # use adapter.config.base for the base or .group_base for the group_base
+ base: adapter.config.group_base,
+
+ # :filter is optional
+ # 'cn' looks for all "cn"s under :base
+ # '*' is the search string - here, it's a wildcard
+ filter: Net::LDAP::Filter.eq('cn', '*'),
+
+ # :attributes is optional
+ # the attributes we want to get returned
+ attributes: %w(dn cn memberuid member submember uniquemember memberof)
+}
+adapter.ldap_search(options)
+```
+
+### Update user accounts when the `dn` and email change
+
+The following will require that any accounts with the new email address are removed.
+Emails have to be unique in GitLab. This is expected to work but unverified as of yet:
+
+```ruby
+# Here's an example with a couple users.
+# Each entry will have to include the old username and the new email
+emails = {
+ 'ORIGINAL_USERNAME' => 'NEW_EMAIL_ADDRESS',
+ ...
+}
+
+emails.each do |username, email|
+ user = User.find_by_username(username)
+ user.email = email
+ user.skip_reconfirmation!
+ user.save!
+end
+
+# Run the UserSync to update the above users' data
+LdapSyncWorker.new.perform
+```
+
+## Routes
+
+### Remove redirecting routes
+
+See <https://gitlab.com/gitlab-org/gitlab-ce/issues/41758#note_54828133>.
+
+```ruby
+path = 'foo'
+conflicting_permanent_redirects = RedirectRoute.matching_path_and_descendants(path)
+
+# Check that conflicting_permanent_redirects is as expected
+conflicting_permanent_redirects.destroy_all
+```
+
+## Merge Requests
+
+### Find Merge Request
+
+```ruby
+m = project.merge_requests.find_by(iid: <IID>)
+m = MergeRequest.find_by_title('NEEDS UNIQUE TITLE!!!')
+```
+
+### Close a merge request properly (if merged but still marked as open)
+
+```ruby
+p = Project.find_by_full_path('')
+m = project.merge_requests.find_by(iid: )
+u = User.find_by_username('')
+MergeRequests::PostMergeService.new(p, u).execute(m)
+```
+
+### Rebase manually
+
+```ruby
+p = Project.find_by_full_path('')
+m = project.merge_requests.find_by(iid: )
+u = User.find_by_username('')
+MergeRequests::RebaseService.new(m.target_project, u).execute(m)
+```
+
+## CI
+
+### Cancel stuck pending pipelines
+
+See <https://gitlab.com/gitlab-com/support-forum/issues/2449#note_41929707>.
+
+```ruby
+Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count
+Ci::Pipeline.where(project_id: p.id).where(status: 'pending').each {|p| p.cancel}
+Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count
+```
+
+### Manually modify runner minutes
+
+```ruby
+Namespace.find_by_full_path("user/proj").namespace_statistics.update(shared_runners_seconds: 27360)
+```
+
+### Remove artifacts more than a week old
+
+```ruby
+### SELECTING THE BUILDS TO CLEAR
+# For a single project:
+project = Project.find_by_full_path('')
+builds_with_artifacts = project.builds.with_artifacts_archive
+
+# Prior to 10.6 the above line would be:
+# builds_with_artifacts = project.builds.with_artifacts
+
+# Instance-wide:
+builds_with_artifacts = Ci::Build.with_artifacts
+
+### CLEAR THEM OUT
+builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.week.ago)
+builds_to_clear.each do |build|
+ build.artifacts_expire_at = Time.now
+ build.erase_erasable_artifacts!
+end
+```
+
+### Find reason failure (for when build trace is empty) (Introduced in 10.3.0)
+
+See <https://gitlab.com/gitlab-org/gitlab-ce/issues/41111>.
+
+```ruby
+build = Ci::Build.find(78420)
+
+build.failure_reason
+
+build.dependencies.each do |d| { puts "status: #{d.status}, finished at: #{d.finished_at},
+ completed: #{d.complete?}, artifacts_expired: #{d.artifacts_expired?}, erased: #{d.erased?}" }
+```
+
+### Disable strict artifact checking (Introduced in GitLab 10.3.0)
+
+See <https://docs.gitlab.com/ee/administration/job_artifacts.html#validation-for-dependencies>.
+
+```ruby
+Feature.enable('ci_disable_validates_dependencies')
+```
+
+### Remove CI traces older than 6 months
+
+```ruby
+current_user = User.find_by_email('cindy@gitlap.com')
+Ci::Build.where("finished_at < ?", 6.months.ago.to_date).each {|b| puts b.id; b.erase(erased_by: current_user) if b.erasable?};nil
+```
+
+### Try CI service
+
+```ruby
+p = Project.find_by_full_path('')
+m = project.merge_requests.find_by(iid: )
+m.project.try(:ci_service)
+```
+
+### Disable AutoDevOps on Existing Projects
+
+```ruby
+Project.all.each do |p|
+ p.auto_devops_attributes={"enabled"=>"0"}
+ p.save
+end
+```
+
+## License
+
+### See license plan name (since v9.3.0-ee)
+
+```ruby
+License.current.plan
+```
+
+### Check if a project feature is available on the instance
+
+Features listed in <https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/app/models/license.rb>.
+
+```ruby
+License.current.feature_available?(:jira_dev_panel_integration)
+```
+
+### Check if a project feature is available in a project
+
+Features listed in <https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/app/models/license.rb>.
+
+```ruby
+p = Project.find_by_full_path('<group>/<project>')
+p.feature_available?(:jira_dev_panel_integration)
+```
+
+### Add a license through the console
+
+```ruby
+key = "<key>"
+license = License.new(data: key)
+license.save
+License.current # check to make sure it applied
+```
+
+## Unicorn
+
+From [Zendesk ticket #91083](https://gitlab.zendesk.com/agent/tickets/91083) (internal)
+
+### Poll unicorn requests by seconds
+
+```ruby
+require 'rubygems'
+require 'unicorn'
+
+# Usage for this program
+def usage
+ puts "ruby unicorn_status.rb <path to unix socket> <poll interval in seconds>"
+ puts "Polls the given Unix socket every interval in seconds. Will not allow you to drop below 3 second poll intervals."
+ puts "Example: /opt/gitlab/embedded/bin/ruby poll_unicorn.rb /var/opt/gitlab/gitlab-rails/sockets/gitlab.socket 10"
+end
+
+# Look for required args. Throw usage and exit if they don't exist.
+if ARGV.count < 2
+ usage
+ exit 1
+end
+
+# Get the socket and threshold values.
+socket = ARGV[0]
+threshold = (ARGV[1]).to_i
+
+# Check threshold - is it less than 3? If so, set to 3 seconds. Safety first!
+if threshold.to_i < 3
+ threshold = 3
+end
+
+# Check - does that socket exist?
+unless File.exist?(socket)
+ puts "Socket file not found: #{socket}"
+ exit 1
+end
+
+# Poll the given socket every THRESHOLD seconds as specified above.
+puts "Running infinite loop. Use CTRL+C to exit."
+puts "------------------------------------------"
+loop do
+ Raindrops::Linux.unix_listener_stats([socket]).each do |addr, stats|
+ puts DateTime.now.to_s + " Active: " + stats.active.to_s + " Queued: " + stats.queued.to_s
+ end
+ sleep threshold
+end
+```
+
+## Sidekiq
+
+### Size of a queue
+
+```ruby
+Sidekiq::Queue.new('background_migration').size
+```
+
+### Kill a worker's Sidekiq jobs
+
+```ruby
+queue = Sidekiq::Queue.new('repository_import')
+queue.each { |job| job.delete if <condition>}
+```
+
+### Enable debug logging of Sidekiq
+
+```ruby
+gitlab_rails['env'] = {
+ 'SIDEKIQ_LOG_ARGUMENTS' => "1"
+}
+```
+
+Then `gitlab-ctl reconfigure; gitlab-ctl restart sidekiq`. The Sidekiq logs will now include additional data for troubleshooting.
+
+### Sidekiq kill signals
+
+See <https://github.com/mperham/sidekiq/wiki/Signals#ttin>.
+
+## Redis
+
+### Connect to redis (omnibus)
+
+```sh
+/opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket
+```
+
+### Connect to redis (HA)
+
+```sh
+/opt/gitlab/embedded/bin/redis-cli -h <host ip> -a <password>
+```
+
+## LFS
+
+### Get info about LFS objects and associated project
+
+```ruby
+o=LfsObject.find_by(oid: "<oid>")
+p=Project.find(LfsObjectsProject.find_by_lfs_object_id(o.id).project_id)
+```
+
+You can then delete these records from the database with:
+
+```ruby
+LfsObjectsProject.find_by_lfs_object_id(o.id).destroy
+o.destroy
+```
+
+You would also want to combine this with deleting the LFS file in the LFS storage
+area on disk. It remains to be seen exactly how or whether the deletion is useful, however.
+
+## Decryption Problems
+
+### Bad Decrypt Script (for encrypted variables)
+
+See <https://gitlab.com/snippets/1730735/raw>.
+
+This script will go through all the encrypted variables and count how many are not able
+to be decrypted. Might be helpful to run on multiple nodes to see which `gitlab-secrets.json`
+file is most up to date:
+
+```bash
+wget -O /tmp/bad-decrypt.rb https://gitlab.com/snippets/1730735/raw
+gitlab-rails runner /tmp/bad-decrypt.rb
+```
+
+If `ProjectImportData Bad count:` is detected and the decision is made to delete the
+encrypted credentials to allow manual reentry:
+
+```ruby
+ # Find the ids of the corrupt ProjectImportData objects
+ total = 0
+ bad = []
+ ProjectImportData.find_each do |data|
+ begin
+ total += 1
+ data.credentials
+ rescue => e
+ bad << data.id
+ end
+ end
+
+ puts "Bad count: #{bad.count} / #{total}"
+
+ # See the bad ProjectImportData ids
+ bad
+
+ # Remove the corrupted credentials
+ import_data = ProjectImportData.where(id: bad)
+ import_data.each do |data|
+ data.update_columns({ encrypted_credentials: nil, encrypted_credentials_iv: nil, encrypted_credentials_salt: nil})
+ end
+```
+
+If `User OTP Secret Bad count:` is detected. For each user listed disable/enable
+two-factor authentication.
+
+### Decrypt Script for encrypted tokens
+
+This script will search for all encrypted tokens that are causing decryption errors,
+and update or reset as needed:
+
+```bash
+wget -O /tmp/encrypted-tokens.rb https://gitlab.com/snippets/1876342/raw
+gitlab-rails runner /tmp/encrypted-tokens.rb
+```
+
+## Geo
+
+### Artifacts
+
+#### Find failed artifacts
+
+```ruby
+Geo::JobArtifactRegistry.failed
+```
+
+#### Download artifact
+
+```ruby
+Gitlab::Geo::JobArtifactDownloader.new(:job_artifact, <artifact_id>).execute
+```
+
+#### Get a count of the synced artifacts
+
+```ruby
+Geo::JobArtifactRegistry.synced.count
+```
+
+#### Find `ID` of synced artifacts that are missing on primary
+
+```ruby
+Geo::JobArtifactRegistry.synced.missing_on_primary.pluck(:artifact_id)
+```
+
+### Repository verification failures
+
+#### Get the number of verification failed repositories
+
+```ruby
+Geo::ProjectRegistryFinder.new.count_verification_failed_repositories
+```
+
+#### Find the verification failed repositories
+
+```ruby
+Geo::ProjectRegistry.verification_failed_repos
+```
+
+### Find repositories that failed to sync
+
+```ruby
+Geo::ProjectRegistryFinder.new.find_failed_project_registries('repository')
+```
+
+### Resync repositories
+
+#### Queue up all repositories for resync. Sidekiq will handle each sync
+
+```ruby
+Geo::ProjectRegistry.update_all(resync_repository: true, resync_wiki: true)
+```
+
+#### Sync individual repository now
+
+```ruby
+project = Project.find_by_full_path('<group/project>')
+
+Geo::RepositorySyncService.new(project).execute
+```
diff --git a/doc/administration/troubleshooting/kubernetes_cheat_sheet.md b/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
index 260af333e8e..6bcd4c48e5a 100644
--- a/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
+++ b/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
@@ -75,7 +75,7 @@ and they will assist you with any issues you are having.
## GitLab-specific kubernetes information
- Minimal config that can be used to test a Kubernetes helm chart can be found
- [here](https://gitlab.com/charts/gitlab/issues/620).
+ [here](https://gitlab.com/gitlab-org/charts/gitlab/issues/620).
- Tailing logs of a separate pod. An example for a unicorn pod:
@@ -176,7 +176,7 @@ and they will assist you with any issues you are having.
helm upgrade <release name> <chart path> -f gitlab.yaml
```
- After <https://canary.gitlab.com/charts/gitlab/issues/780> is fixed, it should
+ After <https://gitlab.com/gitlab-org/charts/gitlab/issues/780> is fixed, it should
be possible to use [Updating GitLab using the Helm Chart](https://docs.gitlab.com/ee/install/kubernetes/gitlab_chart.html#updating-gitlab-using-the-helm-chart)
for upgrades.
@@ -191,8 +191,8 @@ and they will assist you with any issues you are having.
## Installation of minimal GitLab config via Minukube on macOS
-This section is based on [Developing for Kubernetes with Minikube](https://gitlab.com/charts/gitlab/blob/master/doc/minikube/index.md)
-and [Helm](https://gitlab.com/charts/gitlab/blob/master/doc/helm/index.md). Refer
+This section is based on [Developing for Kubernetes with Minikube](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/minikube/index.md)
+and [Helm](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/helm/index.md). Refer
to those documents for details.
- Install Kubectl via Homebrew:
@@ -223,7 +223,7 @@ to those documents for details.
helm init --service-account tiller
```
-- Copy the file <https://gitlab.com/charts/gitlab/raw/master/examples/values-minikube-minimum.yaml>
+- Copy the file <https://gitlab.com/gitlab-org/charts/gitlab/raw/master/examples/values-minikube-minimum.yaml>
to your workstation.
- Find the IP address in the output of `minikube ip` and update the yaml file with
diff --git a/doc/administration/troubleshooting/linux_cheat_sheet.md b/doc/administration/troubleshooting/linux_cheat_sheet.md
new file mode 100644
index 00000000000..2bbb498f020
--- /dev/null
+++ b/doc/administration/troubleshooting/linux_cheat_sheet.md
@@ -0,0 +1,339 @@
+---
+type: reference
+---
+
+# Linux Cheat Sheet
+
+This is the GitLab Support Team's collection of information regarding Linux, that they
+sometimes use while troubleshooting. It is listed here for transparency,
+and it may be useful for users with experience with Linux. If you are currently
+having an issue with GitLab, you may want to check your [support options](https://about.gitlab.com/support/)
+first, before attempting to use this information.
+
+CAUTION: **CAUTION:**
+If you are administering GitLab you are expected to know these commands for your distribution
+of choice. If you are a GitLab Support Engineer, consider this a cross-reference to
+translate `yum` -> `apt-get` and the like.
+
+Note: **Note:**
+Most of the commands below have not been labeled as to which distribution they work
+on. Contributions are welcome to help add them.
+
+## System Commands
+
+### Distro Information
+
+```bash
+# Debian/Ubuntu
+uname -a
+lsb_release -a
+
+# CentOS/RedHat
+cat /etc/centos-release
+cat /etc/redhat-release
+
+# This will provide a lot more information
+cat /etc/os-release
+```
+
+### Shut down or Reboot
+
+```bash
+shutdown -h now
+reboot
+```
+
+### Permissions
+
+```bash
+# change the user:group ownership of a file/dir
+chown root:git <file_or_dir>
+
+# make a file executable
+chmod u+x <file>
+```
+
+### Files & Dirs
+
+```bash
+# create a new directory and all subdirectories
+mkdir -p dir/dir2/dir3
+
+# Send a command's output to file.txt, no STDOUT
+ls > file.txt
+
+# Send a command's output to file.txt AND see it in STDOUT
+ls | tee /tmp/file.txt
+
+# Search and Replace within a file
+sed -i 's/original-text/new-text/g' <filename>
+```
+
+### See all set environment variables
+
+```bash
+env
+```
+
+## Searching
+
+### File names
+
+```bash
+# search for a file in a filesystem
+find . -name 'filename.rb' -print
+
+# locate a file
+locate <filename>
+
+# see command history
+history
+
+# search CLI history
+<ctrl>-R
+```
+
+### File contents
+
+```bash
+# -B/A = show 2 lines before/after search_term
+grep -B 2 -A 2 search_term <filename>
+
+# -<number> shows both before and after
+grep -2 search_term <filename>
+
+# Search on all files in directory (recursively)
+grep -r search_term <directory>
+
+# search through *.gz files is the same except with zgrep
+zgrep search_term <filename>
+
+# Fast grep printing lines containing a string pattern
+fgrep -R string_pattern <filename or directory>
+```
+
+### CLI
+
+```bash
+# View command history
+history
+
+# Run last command that started with 'his' (3 letters min)
+!his
+
+# Search through command history
+<ctrl>-R
+
+# Execute last command with sudo
+sudo !!
+```
+
+## Managing resources
+
+### Memory, Disk, & CPU usage
+
+```bash
+# disk space info. The '-h' gives the data in human-readable values
+df -h
+
+# size of each file/dir and its contents in the current dir
+du -hd 1
+
+# or alternative
+du -h --max-depth=1
+
+# find files greater than certain size(k, M, G) and list them in order
+# get rid of the + for exact, - for less than
+find / -type f -size +100M -print0 | xargs -0 du -hs | sort -h
+
+# Find free memory on a system
+free -m
+
+# Find what processes are using memory/CPU and organize by it
+# Load average is 1/CPU for 1, 5, and 15 minutes
+top -o %MEM
+top -o %CPU
+```
+
+### Strace
+
+```bash
+# strace a process
+strace -tt -T -f -y -s 1024 -p <pid>
+
+# -tt print timestamps with microsecond accuracy
+
+# -T print the time spent in each syscall
+
+# -f also trace any child processes that forked
+
+# -y print the path associated with file handles
+
+# -s max string length to print for an event
+
+# -o output file
+
+# run strace on all unicorn processes
+ps auwx | grep unicorn | awk '{ print " -p " $2}' | xargs strace -tt -T -f -y -s 1024 -o /tmp/unicorn.txt
+```
+
+See the [strace zine](https://wizardzines.com/zines/strace/) for a quick walkthrough.
+
+Brendan Gregg has a more detailed explanation of [how to use strace](http://www.brendangregg.com/blog/2014-05-11/strace-wow-much-syscall.html).
+
+Be aware that strace can have major impacts to system performance when it is running.
+
+### The Strace Parser tool
+
+Our [strace-parser tool](https://gitlab.com/wchandler/strace-parser) can be used to
+provide a high level summary of the `strace` output. It is similar to `strace -C`,
+but provides much more detailed statistics.
+
+MacOS and Linux binaries [are available](https://gitlab.com/gitlab-com/support/toolbox/strace-parser/-/tags),
+or you can build it from source if you have the Rust compiler.
+
+#### How to use the tool
+
+First run the tool with no arguments other than the strace output file name to get
+a summary of the top processes sorted by time spent actively performing tasks. You
+can also sort based on total time, # of syscalls made, PID #, and # of child processes
+using the `-S` or `--sort` flag. The number of results defaults to 25 processes, but
+can be changed using the `-c`/`--count` option. See `--help` for full details.
+
+```sh
+$ ./strace-parser strace.txt
+
+Top 25 PIDs
+-----------
+
+ pid active (ms) wait (ms) total (ms) % active syscalls
+ ---------- ---------- --------- --------- --------- ---------
+ 8795 689.072 45773.832 46462.902 16.89% 23018
+ 13408 679.432 55910.891 56590.320 16.65% 28593
+ 6423 554.822 13175.485 13730.308 13.60% 13735
+...
+```
+
+Based on the summary, you can then view the details of syscalls made by one or more
+procsses using the `-p`/`--pid` for a specific process, or `-s`/`--stats` flags for
+a sorted list. `--stats` takes the same sorting and count options as summary.
+
+```sh
+$ ./strace-parse strace.text -p 6423
+
+PID 6423
+13735 syscalls, active time: 554.822ms, total time: 13730.308ms
+
+ syscall count total max avg min errors
+ (ms) (ms) (ms) (ms)
+ --------------- -------- ---------- ---------- ---------- ---------- --------
+ epoll_wait 628 13175.485 21.259 20.980 0.020
+ clock_gettime 7326 199.500 0.249 0.027 0.013
+ stat 2101 110.768 19.056 0.053 0.017 ENOENT: 2076
+ ...
+ ---------------
+
+ Parent PID: 495
+ Child PIDs: 8383, 8418, 8419, 8420, 8421
+
+ Slowest file access times for PID 6423:
+
+ open (ms) timestamp error file name
+ ----------- --------------- --------------- ----------
+ 29.818 10:53:11.528954 /srv/gitlab-data/builds/2018_08/6174/954448.log
+ 12.309 10:53:46.708274 /srv/gitlab-data/builds/2018_08/5342/954186.log
+ 0.039 10:53:49.222110 /opt/gitlab/embedded/service/gitlab-rails/app/views/events/event/_note.html.haml
+ 0.035 10:53:49.125115 /opt/gitlab/embedded/service/gitlab-rails/app/views/events/event/_push.html.haml
+ ...
+```
+
+In the example above, we can see that file opening times on `/srv/gitlab-data` are
+extremely slow, about 100X slower than `/opt/gitlab`.
+
+When nothing stands out in the results, a good way to get more context is to run `strace`
+on your own GitLab instance while performing the action performed by the customer,
+then compare summaries of both results and dive into the differences.
+
+#### Stats for the open syscall
+
+Rough numbers for calls to `open` and `openat` (used to access files) on various configurations.
+Slow storage can cause the dreaded `DeadlineExceeded` error in Gitaly.
+
+Also [see this entry](https://docs.gitlab.com/ee/administration/operations/filesystem_benchmarking.html)
+in the handbook for quick tests customers can perform to check their filesystem performance.
+
+Keep in mind that timing information from `strace` is often somewhat inaccurate, so
+small differences should not be considered significant.
+
+|Setup | access times |
+|:--------------|:--------------|
+| EFS | 10 - 30ms |
+| Local Storage | 0.01 - 1ms |
+
+## Networking
+
+### Ports
+
+```bash
+# Find the programs that are listening on ports
+netstat -plnt
+ss -plnt
+lsof -i -P | grep <port>
+```
+
+### Internet/DNS
+
+```bash
+# Show domain IP address
+dig +short example.com
+nslookup example.com
+
+# Check DNS using specific nameserver
+# 8.8.8.8 = google, 1.1.1.1 = cloudflare, 208.67.222.222 = opendns
+dig @8.8.8.8 example.com
+nslookup example.com 1.1.1.1
+
+# Find host provider
+whois <ip_address> | grep -i "orgname\|netname"
+
+# Curl headers with redirect
+curl --head --location https://example.com
+```
+
+## Package Management
+
+```bash
+# Debian/Ubuntu
+
+# List packages
+dpkg -l
+apt list --installed
+
+# Find an installed package
+dpkg -l | grep <package>
+apt list --installed | grep <package>
+
+# Install a package
+dpkg -i <package_name>.deb
+apt-get install <package>
+apt install <package>
+
+# CentOS/RedHat
+
+# Install a package
+yum install <package>
+dnf install <package> # RHEL/CentOS 8+
+
+rpm -ivh <package_name>.rpm
+
+# Find an installed package
+rpm -qa | grep <package>
+```
+
+## Logs
+
+```bash
+# Print last lines in log file where 'n'
+# is the number of lines to print
+tail -n /path/to/log/file
+```
diff --git a/doc/administration/troubleshooting/test_environments.md b/doc/administration/troubleshooting/test_environments.md
new file mode 100644
index 00000000000..075effc5dc3
--- /dev/null
+++ b/doc/administration/troubleshooting/test_environments.md
@@ -0,0 +1,126 @@
+---
+type: reference
+---
+
+# Apps for a Testing Environment
+
+This is the GitLab Support Team's collection of information regarding testing environments,
+for use while troubleshooting. It is listed here for transparency, and it may be useful
+for users with experience with these tools. If you are currently having an issue with
+GitLab, you may want to check your [support options](https://about.gitlab.com/support/)
+first, before attempting to use this information.
+
+NOTE: **Note:**
+This page was initially written for Support Engineers, so some of the links
+are only available internally at GitLab.
+
+## Docker
+
+The following were tested on docker containers running in the cloud. Support Engineers,
+please see [these docs](https://gitlab.com/gitlab-com/dev-resources/tree/master/dev-resources#running-docker-containers)
+on how to run Docker containers on `dev-resources`. Other setups haven't been tested,
+but contributions are welcome.
+
+### GitLab
+
+Please see [our Docker test environment docs](https://docs.gitlab.com/ee/install/digitaloceandocker.html#create-new-gitlab-container)
+for how to run GitLab on Docker. When spinning this up with `docker-machine`, ensure
+you change a few things:
+
+1. Update the name of the `docker-machine` host. You can see a list of hosts
+ with `docker-machine ls`.
+1. Expose the necessary ports using the `-p` flag. Docker normally doesn't
+ allow access to any ports it uses outside of the container, so they must be
+ explicitly exposed.
+1. Add any necessary `gitlab.rb` configuration to the
+ `GITLAB_OMNIBUS_CONFIG` variable.
+
+For example, when the `docker-machine` host we want to use is `do-docker`:
+
+```sh
+docker run --detach --name gitlab \
+--env GITLAB_OMNIBUS_CONFIG="external_url 'http://$(docker-machine ip do-docker)'; gitlab_rails['gitlab_shell_ssh_port'] = 2222;" \
+--hostname $(docker-machine ip do-docker) \
+-p 80:80 -p 2222:22 \
+gitlab/gitlab-ee:11.5.3-ee.0
+```
+
+### SAML
+
+#### SAML for Authentication
+
+We can use the [test-saml-idp Docker image](https://hub.docker.com/r/jamedjo/test-saml-idp)
+to do the work for us:
+
+```sh
+docker run --name gitlab_saml -p 8080:8080 -p 8443:8443 \
+-e SIMPLESAMLPHP_SP_ENTITY_ID=<GITLAB_IP_OR_DOMAIN> \
+-e SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE=<GITLAB_IP_OR_DOMAIN>/users/auth/saml/callback \
+-d jamedjo/test-saml-idp
+```
+
+The following will also need to go in your `/etc/gitlab/gitlab.rb`. See [our SAML docs](https://docs.gitlab.com/ee/integration/saml.html)
+for more, as well as the list of [default usernames, passwords, and emails](https://hub.docker.com/r/jamedjo/test-saml-idp/#usage).
+
+```ruby
+gitlab_rails['omniauth_enabled'] = true
+gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
+gitlab_rails['omniauth_sync_email_from_provider'] = 'saml'
+gitlab_rails['omniauth_sync_profile_from_provider'] = ['saml']
+gitlab_rails['omniauth_sync_profile_attributes'] = ['email']
+gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'saml'
+gitlab_rails['omniauth_block_auto_created_users'] = false
+gitlab_rails['omniauth_auto_link_ldap_user'] = false
+gitlab_rails['omniauth_auto_link_saml_user'] = true
+gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "saml",
+ "label" => "SAML",
+ "args" => {
+ assertion_consumer_service_url: '<GITLAB_IP_OR_DOMAIN>/users/auth/saml/callback',
+ idp_cert_fingerprint: '119b9e027959cdb7c662cfd075d9e2ef384e445f',
+ idp_sso_target_url: '<SAML_IP_OR_DOMAIN>:8080/simplesaml/saml2/idp/SSOService.php',
+ issuer: '<GITLAB_IP_OR_DOMAIN>',
+ name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
+ }
+ }
+]
+```
+
+#### GroupSAML for GitLab.com
+
+See [the GDK SAML documentation](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/saml.md).
+
+### ElasticSearch
+
+```sh
+docker run -d --name elasticsearch \
+-p 9200:9200 -p 9300:9300 \
+-e "discovery.type=single-node" \
+docker.elastic.co/elasticsearch/elasticsearch:5.5.1
+```
+
+Then confirm it works in the browser at `curl http://<IP_ADDRESS>:9200/_cat/health`.
+ElasticSearch's default username is `elastic` and password is `changeme`.
+
+### PlantUML
+
+See [our PlantUML docs](../integration/plantuml.md#docker)
+on running PlantUML in Docker.
+
+### Jira
+
+```sh
+docker run -d -p 8081:8080 cptactionhank/atlassian-jira:latest
+```
+
+Then go to `<IP_ADDRESS>:8081` in the browser to set it up. This requires a
+Jira license.
+
+### Grafana
+
+```sh
+docker run -d --name grafana -e "GF_SECURITY_ADMIN_PASSWORD=gitlab" -p 3000:3000 grafana/grafana
+```
+
+Access it at `<IP_ADDRESS>:3000`.
diff --git a/doc/api/groups.md b/doc/api/groups.md
index d7f5b1b463b..8b13462b887 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -156,7 +156,8 @@ Parameters:
| `with_issues_enabled` | boolean | no | Limit by projects with issues feature enabled. Default is `false` |
| `with_merge_requests_enabled` | boolean | no | Limit by projects with merge requests feature enabled. Default is `false` |
| `with_shared` | boolean | no | Include projects shared to this group. Default is `true` |
-| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
+| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
+| `min_access_level` | integer | no | Limit to projects where current user has at least this [access level](members.md) |
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
| `with_security_reports` | boolean | no | **(ULTIMATE)** Return only projects that have security reports artifacts present in any of their builds. This means "projects with security reports enabled". Default is `false` |
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 7498d2d840b..a89a6e7c5cc 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -573,6 +573,18 @@ the `weight` parameter:
}
```
+Users on GitLab [Ultimate](https://about.gitlab.com/pricing/) will additionally see
+the `epic_iid` property:
+
+```json
+{
+ "project_id" : 4,
+ "description" : "Omnis vero earum sunt corporis dolor et placeat.",
+ "epic_iid" : 42,
+ ...
+}
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index 850cf57a06f..8d5b3a65789 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -57,6 +57,19 @@ Example response:
"committer_email":"admin@example.com",
"committed_date":"2019-01-03T01:55:38.000Z"
},
+ "milestone":{
+ "id":51,
+ "iid":1,
+ "project_id":24,
+ "title":"v1.0-rc",
+ "description":"Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state":"closed",
+ "created_at":"2019-07-12T19:45:44.256Z",
+ "updated_at":"2019-07-12T19:45:44.256Z",
+ "due_date":"2019-08-16T11:00:00.256Z",
+ "start_date":"2019-07-30T12:00:00.256Z",
+ "web_url":"http://localhost:3000/root/awesome-app/-/milestones/1"
+ },
"assets":{
"count":6,
"sources":[
@@ -205,6 +218,19 @@ Example response:
"committer_email":"admin@example.com",
"committed_date":"2019-01-03T01:53:28.000Z"
},
+ "milestone":{
+ "id":51,
+ "iid":1,
+ "project_id":24,
+ "title":"v1.0-rc",
+ "description":"Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state":"closed",
+ "created_at":"2019-07-12T19:45:44.256Z",
+ "updated_at":"2019-07-12T19:45:44.256Z",
+ "due_date":"2019-08-16T11:00:00.256Z",
+ "start_date":"2019-07-30T12:00:00.256Z",
+ "web_url":"http://localhost:3000/root/awesome-app/-/milestones/1"
+ },
"assets":{
"count":4,
"sources":[
@@ -240,23 +266,24 @@ Create a Release. You need push access to the repository to create a Release.
POST /projects/:id/releases
```
-| Attribute | Type | Required | Description |
-| -------------------| -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). |
-| `name` | string | yes | The release name. |
-| `tag_name` | string | yes | The tag where the release will be created from. |
-| `description` | string | yes | The description of the release. You can use [markdown](../../user/markdown.md). |
-| `ref` | string | no | If `tag_name` doesn't exist, the release will be created from `ref`. It can be a commit SHA, another tag name, or a branch name. |
-| `assets:links` | array of hash | no | An array of assets links. |
-| `assets:links:name`| string | required by: `assets:links` | The name of the link. |
-| `assets:links:url` | string | required by: `assets:links` | The url of the link. |
-| `released_at` | datetime | no | The date when the release will be/was ready. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
+| Attribute | Type | Required | Description |
+| -------------------| --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). |
+| `name` | string | yes | The release name. |
+| `tag_name` | string | yes | The tag where the release will be created from. |
+| `description` | string | yes | The description of the release. You can use [markdown](../../user/markdown.md). |
+| `ref` | string | no | If `tag_name` doesn't exist, the release will be created from `ref`. It can be a commit SHA, another tag name, or a branch name. |
+| `milestone` | string | no | The title of the milestone the release is associated with. |
+| `assets:links` | array of hash | no | An array of assets links. |
+| `assets:links:name`| string | required by: `assets:links` | The name of the link. |
+| `assets:links:url` | string | required by: `assets:links` | The url of the link. |
+| `released_at` | datetime | no | The date when the release will be/was ready. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
Example request:
```sh
curl --header 'Content-Type: application/json' --header "PRIVATE-TOKEN: gDybLx3yrUK_HLp3qPjS" \
- --data '{ "name": "New release", "tag_name": "v0.3", "description": "Super nice release", "assets": { "links": [{ "name": "hoge", "url": "https://google.com" }] } }' \
+ --data '{ "name": "New release", "tag_name": "v0.3", "description": "Super nice release", "milestone": "v1.0-rc", "assets": { "links": [{ "name": "hoge", "url": "https://google.com" }] } }' \
--request POST https://gitlab.example.com/api/v4/projects/24/releases
```
@@ -294,6 +321,19 @@ Example response:
"committer_email":"admin@example.com",
"committed_date":"2019-01-03T01:55:38.000Z"
},
+ "milestone":{
+ "id":51,
+ "iid":1,
+ "project_id":24,
+ "title":"v1.0-rc",
+ "description":"Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state":"active",
+ "created_at":"2019-07-12T19:45:44.256Z",
+ "updated_at":"2019-07-12T19:45:44.256Z",
+ "due_date":"2019-08-16T11:00:00.256Z",
+ "start_date":"2019-07-30T12:00:00.256Z",
+ "web_url":"http://localhost:3000/root/awesome-app/-/milestones/1"
+ },
"assets":{
"count":5,
"sources":[
@@ -334,18 +374,19 @@ Update a Release.
PUT /projects/:id/releases/:tag_name
```
-| Attribute | Type | Required | Description |
-| ------------- | -------------- | -------- | -------------------------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). |
-| `tag_name` | string | yes | The tag where the release will be created from. |
-| `name` | string | no | The release name. |
-| `description` | string | no | The description of the release. You can use [markdown](../../user/markdown.md). |
-| `released_at` | datetime | no | The date when the release will be/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
+| Attribute | Type | Required | Description |
+| ------------- | -------------- | -------- | --------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). |
+| `tag_name` | string | yes | The tag where the release will be created from. |
+| `name` | string | no | The release name. |
+| `description` | string | no | The description of the release. You can use [markdown](../../user/markdown.md). |
+| `milestone` | string | no | The title of the milestone to associate with the release (`""` to remove the milestone from the release). |
+| `released_at` | datetime | no | The date when the release will be/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
Example request:
```sh
-curl --request PUT --data name="new name" --header "PRIVATE-TOKEN: gDybLx3yrUK_HLp3qPjS" "https://gitlab.example.com/api/v4/projects/24/releases/v0.1"
+curl --header 'Content-Type: application/json' --request PUT --data '{"name": "new name", "milestone": "v1.0"}' --header "PRIVATE-TOKEN: gDybLx3yrUK_HLp3qPjS" "https://gitlab.example.com/api/v4/projects/24/releases/v0.1"
```
Example response:
@@ -382,6 +423,19 @@ Example response:
"committer_email":"admin@example.com",
"committed_date":"2019-01-03T01:53:28.000Z"
},
+ "milestone":{
+ "id":53,
+ "iid":2,
+ "project_id":24,
+ "title":"v1.0",
+ "description":"Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state":"active",
+ "created_at":"2019-09-01T13:00:00.256Z",
+ "updated_at":"2019-09-01T13:00:00.256Z",
+ "due_date":"2019-09-20T13:00:00.256Z",
+ "start_date":"2019-09-05T12:00:00.256Z",
+ "web_url":"http://localhost:3000/root/awesome-app/-/milestones/3"
+ },
"assets":{
"count":4,
"sources":[
diff --git a/doc/api/templates/dockerfiles.md b/doc/api/templates/dockerfiles.md
index a08b8d33693..ee271c31b49 100644
--- a/doc/api/templates/dockerfiles.md
+++ b/doc/api/templates/dockerfiles.md
@@ -1,5 +1,13 @@
+---
+type: reference
+---
+
# Dockerfiles API
+In GitLab, there is an API endpoint available for Dockerfiles. For more
+information on Dockerfiles, see the
+[Docker documentation](https://docs.docker.com/engine/reference/builder/).
+
## List Dockerfile templates
Get all Dockerfile templates.
@@ -111,3 +119,15 @@ Example response:
"content": "# This file is a template, and might need editing before it works on your project.\n# This Dockerfile installs a compiled binary into a bare system.\n# You must either commit your compiled binary into source control (not recommended)\n# or build the binary first as part of a CI/CD pipeline.\n\nFROM buildpack-deps:jessie\n\nWORKDIR /usr/local/bin\n\n# Change `app` to whatever your binary is called\nAdd app .\nCMD [\"./app\"]\n"
}
```
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/api/templates/gitignores.md b/doc/api/templates/gitignores.md
index bf6a914e120..0b6d944cb62 100644
--- a/doc/api/templates/gitignores.md
+++ b/doc/api/templates/gitignores.md
@@ -1,4 +1,12 @@
-# `.gitignore` API
+---
+type: reference
+---
+
+# .gitignore API
+
+In GitLab, there is an API endpoint available for `.gitignore`. For more
+information on `gitignore`, see the
+[Git documentation](https://git-scm.com/docs/gitignore).
## List `.gitignore` templates
@@ -123,3 +131,15 @@ Example response:
"content": "*.gem\n*.rbc\n/.config\n/coverage/\n/InstalledFiles\n/pkg/\n/spec/reports/\n/spec/examples.txt\n/test/tmp/\n/test/version_tmp/\n/tmp/\n\n# Used by dotenv library to load environment variables.\n# .env\n\n## Specific to RubyMotion:\n.dat*\n.repl_history\nbuild/\n*.bridgesupport\nbuild-iPhoneOS/\nbuild-iPhoneSimulator/\n\n## Specific to RubyMotion (use of CocoaPods):\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n# vendor/Pods/\n\n## Documentation cache and generated files:\n/.yardoc/\n/_yardoc/\n/doc/\n/rdoc/\n\n## Environment normalization:\n/.bundle/\n/vendor/bundle\n/lib/bundler/man/\n\n# for a library or gem, you might want to ignore these files since the code is\n# intended to run in multiple environments; otherwise, check them in:\n# Gemfile.lock\n# .ruby-version\n# .ruby-gemset\n\n# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:\n.rvmrc\n"
}
```
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/api/templates/gitlab_ci_ymls.md b/doc/api/templates/gitlab_ci_ymls.md
index 11ec7360e06..80f94b953e3 100644
--- a/doc/api/templates/gitlab_ci_ymls.md
+++ b/doc/api/templates/gitlab_ci_ymls.md
@@ -1,5 +1,13 @@
+---
+type: reference
+---
+
# GitLab CI YMLs API
+In GitLab, there is an API endpoint available to work with CI YMLs. For more
+information on CI/CD pipeline configuration in GitLab, see the
+[configuration reference documentation](../../ci/yaml/README.md).
+
## List GitLab CI YML templates
Get all GitLab CI YML templates.
@@ -123,3 +131,15 @@ Example response:
"content": "# This file is a template, and might need editing before it works on your project.\n# Official language image. Look for the different tagged releases at:\n# https://hub.docker.com/r/library/ruby/tags/\nimage: \"ruby:2.5\"\n\n# Pick zero or more services to be used on all builds.\n# Only needed when using a docker container to run your tests in.\n# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service\nservices:\n - mysql:latest\n - redis:latest\n - postgres:latest\n\nvariables:\n POSTGRES_DB: database_name\n\n# Cache gems in between builds\ncache:\n paths:\n - vendor/ruby\n\n# This is a basic example for a gem or script which doesn't use\n# services such as redis or postgres\nbefore_script:\n - ruby -v # Print out ruby version for debugging\n # Uncomment next line if your rails app needs a JS runtime:\n # - apt-get update -q && apt-get install nodejs -yqq\n - bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby\n\n# Optional - Delete if not using `rubocop`\nrubocop:\n script:\n - rubocop\n\nrspec:\n script:\n - rspec spec\n\nrails:\n variables:\n DATABASE_URL: \"postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB\"\n script:\n - rails db:migrate\n - rails db:seed\n - rails test\n\n# This deploy job uses a simple deploy flow to Heroku, other providers, e.g. AWS Elastic Beanstalk\n# are supported too: https://github.com/travis-ci/dpl\ndeploy:\n type: deploy\n environment: production\n script:\n - gem install dpl\n - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_PRODUCTION_KEY\n"
}
```
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/api/templates/licenses.md b/doc/api/templates/licenses.md
index 5feb1e498bd..92466c73bd3 100644
--- a/doc/api/templates/licenses.md
+++ b/doc/api/templates/licenses.md
@@ -1,5 +1,14 @@
+---
+type: reference
+---
+
# Licenses API
+In GitLab, there is an API endpoint available for working with various open
+source license templates. For more information on the terms of various
+licenses, see [this site](https://choosealicense.com/) or any of the many other
+resources available online.
+
## List license templates
Get all license templates.
@@ -145,3 +154,15 @@ Example response:
"content": "The MIT License (MIT)\n\nCopyright (c) 2016 John Doe\n [...]"
}
```
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index 730e46f994e..a48da557e09 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -580,9 +580,10 @@ For private and internal projects:
If you want to use your own Docker images for docker-in-docker there are a few things you need to do in addition to the steps in the [docker-in-docker](#use-docker-in-docker-workflow-with-docker-executor) section:
1. Update the `image` and `service` to point to your registry.
-1. Add a service [alias](https://docs.gitlab.com/ee/ci/yaml/#servicesalias)
+1. Add a service [alias](https://docs.gitlab.com/ee/ci/yaml/#servicesalias).
-Below is an example of how your `.gitlab-ci.yml` should look like, assuming you have it configured with [TLS enabled](#tls-enabled):
+Below is an example of what your `.gitlab-ci.yml` should look like,
+assuming you have it configured with [TLS enabled](#tls-enabled):
```yaml
build:
@@ -603,7 +604,7 @@ Below is an example of how your `.gitlab-ci.yml` should look like, assuming you
- docker run my-docker-image /script/to/run/tests
```
-If you forget to set the service alias the `docker:19.03.1` image won't find the
+If you forget to set the service alias, the `docker:19.03.1` image won't find the
`dind` service, and an error like the following is thrown:
```sh
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index f6c47a99712..c2d444cb1d6 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -675,9 +675,10 @@ fetch line:
fetch = +refs/environments/*:refs/remotes/origin/environments/*
```
-### Scoping environments with specs **(PREMIUM)**
+### Scoping environments with specs
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2112) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.4.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2112) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.4.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30779) to Core in Gitlab 12.2.
You can limit the environment scope of a variable by
defining which environments it can be available for.
diff --git a/doc/ci/large_repositories/index.md b/doc/ci/large_repositories/index.md
index 29d649ad717..b1359537fca 100644
--- a/doc/ci/large_repositories/index.md
+++ b/doc/ci/large_repositories/index.md
@@ -84,7 +84,7 @@ Fork workflow from GitLab Runner's perspective is stored as a separate repositor
with separate worktree. That means that GitLab Runner cannot optimize the usage
of worktrees and you might have to instruct GitLab Runner to use that.
-In such cases, ideally you want to make the GitLab Runner executor be used only used only
+In such cases, ideally you want to make the GitLab Runner executor be used only
for the given project and not shared across different projects to make this
process more efficient.
diff --git a/doc/ci/multi_project_pipelines.md b/doc/ci/multi_project_pipelines.md
index 61f260cb70d..377ae9717b2 100644
--- a/doc/ci/multi_project_pipelines.md
+++ b/doc/ci/multi_project_pipelines.md
@@ -176,6 +176,18 @@ Upstream pipelines take precedence over downstream ones. If there are two
variables with the same name defined in both upstream and downstream projects,
the ones defined in the upstream project will take precedence.
+### Mirroring status from triggered pipeline
+
+You can mirror the pipeline status from the triggered pipeline to the source
+bridge job by using `strategy: depend`. For example:
+
+```yaml
+trigger_job:
+ trigger:
+ project: my/project
+ strategy: depend
+```
+
### Mirroring status from upstream pipeline
You can mirror the pipeline status from an upstream pipeline to a bridge job by
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 5a15b907da0..438b7c03b51 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -401,7 +401,7 @@ Once you set them, they will be available for all subsequent pipelines.
You can limit the environment scope of a variable by
[defining which environments][envs] it can be available for.
-To learn more about about scoping environments, see [Scoping environments with specs](../environments.md#scoping-environments-with-specs-premium).
+To learn more about about scoping environments, see [Scoping environments with specs](../environments.md#scoping-environments-with-specs).
### Deployment environment variables
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 06bd9e68a18..bfba21646b5 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -100,7 +100,7 @@ The following table lists available parameters for jobs:
| [`stage`](#stage) | Defines a job stage (default: `test`). |
| [`only`](#onlyexcept-basic) | Limit when jobs are created. Also available: [`only:refs`, `only:kubernetes`, `only:variables`, and `only:changes`](#onlyexcept-advanced). |
| [`except`](#onlyexcept-basic) | Limit when jobs are not created. Also available: [`except:refs`, `except:kubernetes`, `except:variables`, and `except:changes`](#onlyexcept-advanced). |
-| [`rules`](#rules) | List of conditions to evaluate and determine selected attributes of a build and whether or not it is created. May not be used alongside `only`/`except`.
+| [`rules`](#rules) | List of conditions to evaluate and determine selected attributes of a job, and whether or not it is created. May not be used alongside `only`/`except`. |
| [`tags`](#tags) | List of tags which are used to select Runner. |
| [`allow_failure`](#allow_failure) | Allow job to fail. Failed job doesn't contribute to commit status. |
| [`when`](#when) | When to run job. Also available: `when:manual` and `when:delayed`. |
@@ -113,7 +113,7 @@ The following table lists available parameters for jobs:
| [`parallel`](#parallel) | How many instances of a job should be run in parallel. |
| [`trigger`](#trigger-premium) | Defines a downstream pipeline trigger. |
| [`include`](#include) | Allows this job to include external YAML files. Also available: `include:local`, `include:file`, `include:template`, and `include:remote`. |
-| [`extends`](#extends) | Configuration entries that this job is going to inherit from. |
+| [`extends`](#extends) | Configuration entries that this job is going to inherit from. |
| [`pages`](#pages) | Upload the result of a job to use with GitLab Pages. |
| [`variables`](#variables) | Define job variables on a job level. |
@@ -693,31 +693,41 @@ and triggers the `docker build service one` job.
### `rules`
-Using `rules` allows for a list of individual rule objects to be evaluated
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29011) in GitLab 12.3.
+
+`rules` allows for a list of individual rule objects to be evaluated
*in order*, until one matches and dynamically provides attributes to the job.
Available rule clauses include:
-- `if` (similar to [`only:variables`](#onlyvariablesexceptvariables)).
-- `changes` (same as [`only:changes`](#onlychangesexceptchanges)).
+- [`if`](#rulesif)
+ (similar to [`only:variables`](#onlyvariablesexceptvariables)).
+- [`changes`](#ruleschanges)
+ (same as [`only:changes`](#onlychangesexceptchanges)).
-For example, using `if`:
+For example, using `if`. This configuration specifies that `job` should be built
+and run for every pipeline on merge requests targeting `master`, regardless of
+the status of other builds:
```yaml
job:
script: "echo Hello, Rules!"
rules:
- - if: '$CI_MERGE_REQUEST_TARGET_BRANCH == "master"' # This rule will be evaluated
+ - if: '$CI_MERGE_REQUEST_TARGET_BRANCH == "master"'
when: always
- - if: '$VAR =~ /pattern/' # This rule will only be evaluated if the first does not match
+ - if: '$VAR =~ /pattern/'
when: manual
- - when: on_success # A Rule entry with no conditional clauses evaluates to true. If neither of the first two Rules match, this one will and set job:when to "on_success"
+ - when: on_success
```
-If the first rule does not match, further rules will be evaluated sequentially
-until a match is found. The above configuration will specify that `job` should
-be built and run for every pipeline on merge requests targeting `master`,
-regardless of the status of other builds.
+In this example, if the first rule:
+
+- Matches, the job will be given the `when:always` attribute.
+- Does not match, the second and third rules will be evaluated sequentially
+ until a match is found. That is, the job will be given either the:
+ - `when: manual` attribute if the second rule matches.
+ - `when: on_success` attribute if the second rule does not match. The third
+ rule will always match when reached because it has no conditional clauses.
#### `rules:if`
@@ -744,10 +754,9 @@ at all, the behavior defaults to `job:when`, which continues to default to
#### `rules:changes`
`changes` works exactly the same way as [`only`/`except`](#onlychangesexceptchanges),
-accepting an array of paths. The following configuration configures a job to be
-run manually if `Dockerfile` has changed OR `$VAR == "string value"`. Otherwise
-it is set to `when:on_success` by the last rule, where 0 clauses evaluate as
-vacuously true.
+accepting an array of paths.
+
+For example:
```yaml
docker build:
@@ -762,12 +771,20 @@ docker build:
```
-#### Complex Rule Clauses
+In this example, a job either set to:
+
+- Run manually if `Dockerfile` has changed OR `$VAR == "string value"`.
+- `when:on_success` by the last rule, where no earlier clauses evaluate to true.
+
+#### Complex rule clauses
To conjoin `if` and `changes` clauses with an AND, use them in the same rule.
-Here we run the job manually if `Dockerfile` or any file in `docker/scripts/`
-has changed AND `$VAR == "string value"`. Otherwise, the job will not be
-included in the pipeline.
+
+In the following example:
+
+- We run the job manually if `Dockerfile` or any file in `docker/scripts/`
+ has changed AND `$VAR == "string value"`.
+- Otherwise, the job will not be included in the pipeline.
```yaml
docker build:
@@ -781,18 +798,27 @@ docker build:
# - when: never would be redundant here, this is implied any time rules are listed.
```
-The only clauses currently available are `if` and `changes`. Keywords such as
-`branches` or `refs` that are currently available for `only`/`except` are not
-yet available in `rules` as they are being individually considered for their
-usage and behavior in the newer context.
+The only clauses currently available are:
+
+- `if`
+- `changes`
+
+Keywords such as `branches` or `refs` that are currently available for
+`only`/`except` are not yet available in `rules` as they are being individually
+considered for their usage and behavior in this context.
#### Permitted attributes
-The only job attributes currently set by `rules` are `when` and `start_in`, if
-`when` is set to `delayed`. A job will be included in a pipeline if `when` is
-evaluated to any value except `never`.
+The only job attributes currently set by `rules` are:
+
+- `when`.
+- `start_in`, if `when` is set to `delayed`.
+
+A job will be included in a pipeline if `when` is evaluated to any value
+except `never`.
-Delayed jobs require a `start_in` value, so rule objects do as well. For example:
+Delayed jobs require a `start_in` value, so rule objects do as well. For
+example:
```yaml
docker build:
@@ -806,9 +832,9 @@ docker build:
```
-Additional Job configuration may be added to rules in the future, if something
-useful isn't available, please open an issue on
-[Gitlab CE](https://www.gitlab.com/gitlab-org/gitlab-ce/issues).
+Additional job configuration may be added to rules in the future. If something
+useful isn't available, please
+[open an issue](https://www.gitlab.com/gitlab-org/gitlab-ce/issues).
### `tags`
@@ -1801,7 +1827,8 @@ and bring back the old behavior.
### `needs`
-> Introduced in GitLab 12.2.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/47063) in GitLab 12.2.
+> - In GitLab 12.3, maximum number of jobs in `needs` array raised from five to 50.
The `needs:` keyword enables executing jobs out-of-order, allowing you to implement
a [directed acyclic graph](../directed_acyclic_graph/index.md) in your `.gitlab-ci.yml`.
@@ -1852,30 +1879,26 @@ This example creates three paths of execution:
#### Requirements and limitations
-1. If `needs:` is set to point to a job that is not instantiated
- because of `only/except` rules or otherwise does not exist, the
- job will fail.
-1. Note that on day one of the launch, we are temporarily limiting the
- maximum number of jobs that a single job can need in the `needs:` array. Track
- our [infrastructure issue](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues/7541)
- for details on the current limit.
-1. If you use `dependencies:` with `needs:`, it's important that you
- do not mark a job as having a dependency on something that won't
- have been run at the time it needs it. It's better to use both
- keywords in this case so that GitLab handles the ordering appropriately.
-1. It is impossible for now to have `needs: []` (empty needs),
- the job always needs to depend on something, unless this is the job
- in the first stage (see [gitlab-ce#65504](https://gitlab.com/gitlab-org/gitlab-ce/issues/65504)).
-1. If `needs:` refers to a job that is marked as `parallel:`.
- the current job will depend on all parallel jobs created.
-1. `needs:` is similar to `dependencies:` in that it needs to use jobs from
- prior stages, meaning it is impossible to create circular
- dependencies or depend on jobs in the current stage (see [gitlab-ce#65505](https://gitlab.com/gitlab-org/gitlab-ce/issues/65505)).
-1. Related to the above, stages must be explicitly defined for all jobs
- that have the keyword `needs:` or are referred to by one.
-1. For self-managed users, the feature must be turned on using the `ci_dag_support`
- feature flag. The `ci_dag_limit_needs` option, if set, will limit the number of
- jobs that a single job can need to `50`. If unset, the limit is `5`.
+- If `needs:` is set to point to a job that is not instantiated
+ because of `only/except` rules or otherwise does not exist, the
+ pipeline will be created with YAML error.
+- We are temporarily limiting the maximum number of jobs that a single job can
+ need in the `needs:` array:
+ - For GitLab.com, the limit is five. For more information, see our
+ [infrastructure issue](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues/7541).
+ - For self-managed instances, the limit is:
+ - Five by default (`ci_dag_limit_needs` feature flag is enabled).
+ - 50 if the `ci_dag_limit_needs` feature flag is disabled.
+- It is impossible for now to have `needs: []` (empty needs),
+ the job always needs to depend on something, unless this is the job
+ in the first stage (see [gitlab-ce#65504](https://gitlab.com/gitlab-org/gitlab-ce/issues/65504)).
+- If `needs:` refers to a job that is marked as `parallel:`.
+ the current job will depend on all parallel jobs created.
+- `needs:` is similar to `dependencies:` in that it needs to use jobs from
+ prior stages, meaning it is impossible to create circular
+ dependencies or depend on jobs in the current stage (see [gitlab-ce#65505](https://gitlab.com/gitlab-org/gitlab-ce/issues/65505)).
+- Related to the above, stages must be explicitly defined for all jobs
+ that have the keyword `needs:` or are referred to by one.
### `coverage`
diff --git a/doc/development/README.md b/doc/development/README.md
index 3912a828dec..bbe73570f49 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -22,6 +22,7 @@ description: 'Learn how to contribute to GitLab.'
- [Guidelines for implementing Enterprise Edition features](ee_features.md)
- [Security process for developers](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#security-releases-critical-non-critical-as-a-developer)
- [Requesting access to Chatops on GitLab.com](chatops_on_gitlabcom.md#requesting-access) (for GitLabbers)
+- [Danger bot](dangerbot.md)
## UX and Frontend guides
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 2adca2dae28..ee5fc553e27 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -651,7 +651,7 @@ We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/ha
[shell-charts]: https://docs.gitlab.com/charts/charts/gitlab/gitlab-shell/
[shell-source]: ../install/installation.md#install-gitlab-shell
[pages-omnibus]: ../administration/pages/index.md
-[pages-charts]: https://gitlab.com/charts/gitlab/issues/37
+[pages-charts]: https://gitlab.com/gitlab-org/charts/gitlab/issues/37
[pages-source]: ../install/installation.md#install-gitlab-pages
[pages-gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/pages.md
[registry-omnibus]: ../administration/container_registry.md#container-registry-domain-configuration
@@ -673,9 +673,9 @@ We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/ha
[grafana-omnibus]: ../administration/monitoring/performance/grafana_configuration.md
[grafana-charts]: https://github.com/helm/charts/tree/master/stable/grafana
[sentry-omnibus]: https://docs.gitlab.com/omnibus/settings/configuration.html#error-reporting-and-logging-with-sentry
-[sentry-charts]: https://gitlab.com/charts/gitlab/issues/1319
+[sentry-charts]: https://gitlab.com/gitlab-org/charts/gitlab/issues/1319
[jaeger-omnibus]: https://gitlab.com/gitlab-org/omnibus-gitlab/issues/4104
-[jaeger-charts]: https://gitlab.com/charts/gitlab/issues/1320
+[jaeger-charts]: https://gitlab.com/gitlab-org/charts/gitlab/issues/1320
[jaeger-source]: ../development/distributed_tracing.md#enabling-distributed-tracing
[jaeger-gdk]: ../development/distributed_tracing.html#using-jaeger-in-the-gitlab-development-kit
[redis-exporter-omnibus]: ../administration/monitoring/prometheus/redis_exporter.md
@@ -687,7 +687,7 @@ We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/ha
[gitlab-monitor-omnibus]: ../administration/monitoring/prometheus/gitlab_monitor_exporter.md
[gitlab-monitor-charts]: https://docs.gitlab.com/charts/charts/gitlab/gitlab-monitor/index.html
[node-exporter-omnibus]: ../administration/monitoring/prometheus/node_exporter.md
-[node-exporter-charts]: https://gitlab.com/charts/gitlab/issues/1332
+[node-exporter-charts]: https://gitlab.com/gitlab-org/charts/gitlab/issues/1332
[mattermost-omnibus]: https://docs.gitlab.com/omnibus/gitlab-mattermost/
[mattermost-charts]: https://docs.mattermost.com/install/install-mmte-helm-gitlab-helm.html
[minio-omnibus]: https://min.io/download
@@ -705,7 +705,7 @@ We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/ha
[certificate-management-source]: ../install/installation.md#using-https
[certificate-management-gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/https.md
[geo-omnibus]: ../administration/geo/replication/index.md#setup-instructions
-[geo-charts]: https://gitlab.com/charts/gitlab/issues/8
+[geo-charts]: https://gitlab.com/gitlab-org/charts/gitlab/issues/8
[geo-gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/geo.md
[ldap-omnibus]: ../administration/auth/ldap.md
[ldap-charts]: https://docs.gitlab.com/charts/charts/globals.html#ldap
diff --git a/doc/development/background_migrations.md b/doc/development/background_migrations.md
index 3fd95537eaa..a456bbc781f 100644
--- a/doc/development/background_migrations.md
+++ b/doc/development/background_migrations.md
@@ -61,8 +61,8 @@ migration classes must be defined in the namespace
## Scheduling
-Scheduling a migration can be done in either a regular migration or a
-post-deployment migration. To do so, simply use the following code while
+Scheduling a background migration should be done in a post-deployment migration.
+To do so, simply use the following code while
replacing the class name and arguments with whatever values are necessary for
your migration:
@@ -283,10 +283,13 @@ the `services.properties` column.
## Testing
-It is required to write tests for background migrations' scheduling migration
-(either a regular migration or a post deployment migration), background
-migration itself and a cleanup migration. You can use the `:migration` RSpec
-tag when testing a regular / post deployment migration.
+It is required to write tests for:
+
+- The background migrations' scheduling migration.
+- The background migration itself.
+- A cleanup migration.
+
+You can use the `:migration` RSpec tag when testing the migrations.
See [README][migrations-readme].
When you do that, keep in mind that `before` and `after` RSpec hooks are going
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index b7d74b17eb3..bcfc0734c06 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -34,7 +34,7 @@ more than one approval, the last maintainer to review and approve it will also m
### Reviewer roulette
-The `danger-review` CI job will randomly pick a reviewer and a maintainer for
+The [Danger bot](dangerbot.md) randomly picks a reviewer and a maintainer for
each area of the codebase that your merge request seems to touch. It only makes
recommendations - feel free to override it if you think someone else is a better
fit!
@@ -116,8 +116,13 @@ warrant a comment could be:
- Any benchmarking performed to complement the change
- Potentially insecure code
-Do not add these comments directly to the source code, unless the
-reviewer requires you to do so.
+Avoid:
+
+- Adding comments (referenced above, or TODO items) directly to the source code unless the reviewer requires you to do so. If the comments are added due to an actionable task,
+a link to an issue must be included.
+- Assigning merge requests with failed tests to maintainers. If the tests are failing and you have to assign, ensure you leave a comment with an explanation.
+- Excessively mentioning maintainers through email or Slack (if the maintainer is reachable
+through Slack). If you can't assign a merge request, `@` mentioning a maintainer in a comment is acceptable and in all other cases assigning the merge request is sufficient.
This
[saves reviewers time and helps authors catch mistakes earlier](https://www.ibm.com/developerworks/rational/library/11-proven-practices-for-peer-review/index.html#__RefHeading__97_174136755).
diff --git a/doc/development/dangerbot.md b/doc/development/dangerbot.md
new file mode 100644
index 00000000000..5fc5886e3a2
--- /dev/null
+++ b/doc/development/dangerbot.md
@@ -0,0 +1,116 @@
+# Danger bot
+
+The GitLab CI pipeline includes a `danger-review` job that uses [Danger](https://github.com/danger/danger)
+to perform a variety of automated checks on the code under test.
+
+Danger is a gem that runs in the CI environment, like any other analysis tool.
+What sets it apart from, e.g., Rubocop, is that it's designed to allow you to
+easily write arbitrary code to test properties of your code or changes. To this
+end, it provides a set of common helpers and access to information about what
+has actually changed in your environment, then simply runs your code!
+
+If Danger is asking you to change something about your merge request, it's best
+just to make the change. If you want to learn how Danger works, or make changes
+to the existing rules, then this is the document for you.
+
+## Operation
+
+On startup, Danger reads a [`Dangerfile`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/Dangerfile)
+from the project root. GitLab's Danger code is decomposed into a set of helpers
+and plugins, all within the [`danger/`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/danger/)
+subdirectory, so ours just tells Danger to load it all. Danger will then run
+each plugin against the merge request, collecting the output from each. A plugin
+may output notifications, warnings, or errors, all of which are copied to the
+CI job's log. If an error happens, the CI job (and so the entire pipeline) will
+be failed.
+
+On merge requests, Danger will also copy the output to a comment on the MR
+itself, increasing visibility.
+
+## Development guidelines
+
+Danger code is Ruby code, so all our [usual backend guidelines](README.md#backend-guides)
+continue to apply. However, there are a few things that deserve special emphasis.
+
+### When to use Danger
+
+Danger is a powerful tool and flexible tool, but not always the most appropriate
+way to solve a given problem or workflow.
+
+First, be aware of GitLab's [commitment to dogfooding](https://about.gitlab.com/handbook/engineering/#dogfooding).
+The code we write for Danger is GitLab-specific, and it **may not** be most
+appropriate place to implement functionality that addresses a need we encounter.
+Our users, customers, and even our own satellite projects, such as [Gitaly](https://gitlab.com/gitlab-org/gitaly),
+often face similar challenges, after all. Think about how you could fulfil the
+same need while ensuring everyone can benefit from the work, and do that instead
+if you can.
+
+If a standard tool (e.g. `rubocop`) exists for a task, it is better to use it
+directly, rather than calling it via Danger. Running and debugging the results
+of those tools locally is easier if Danger isn't involved, and unless you're
+using some Danger-specific functionality, there's no benefit to including it in
+the Danger run.
+
+Danger is well-suited to prototyping and rapidly iterating on solutions, so if
+what we want to build is unclear, a solution in Danger can be thought of as a
+trial run to gather information about a product area. If you're doing this, make
+sure the problem you're trying to solve, and the outcomes of that prototyping,
+are captured in an issue or epic as you go along. This will help us to address
+the need as part of the product in a future version of GitLab!
+
+### Implementation details
+
+Implement each task as an isolated piece of functionality and place it in its
+own directory under `danger` as `danger/<task-name>/Dangerfile`.
+
+Add a line to the top-level `Dangerfile` to ensure it is loaded like:
+
+```ruby
+danger.import_dangerfile('danger/<task-name>')
+```
+
+Each task should be isolated from the others, and able to function in isolation.
+If there is code that should be shared between multiple tasks, add a plugin to
+`danger/plugins/...` and require it in each task that needs it. You can also
+create plugins that are specific to a single task, which is a natural place for
+complex logic related to that task.
+
+Danger code is just Ruby code. It should adhere to our coding standards, and
+needs tests, like any other piece of Ruby in our codebase. However, we aren't
+able to test a `Dangerfile` directly! So, to maximise test coverage, try to
+minimize the number of lines of code in `danger/`. A non-trivial `Dangerfile`
+should mostly call plugin code with arguments derived from the methods provided
+by Danger. The plugin code itself should have unit tests.
+
+At present, we do this by putting the code in a module in `lib/gitlab/danger/...`,
+and including it in the matching `danger/plugins/...` file. Specs can then be
+added in `spec/lib/gitlab/danger/...`.
+
+You'll only know if your `Dangerfile` works by pushing the branch that contains
+it to GitLab. This can be quite frustrating, as it significantly increases the
+cycle time when developing a new task, or trying to debug something in an
+existing one. If you've followed the guidelines above, most of your code can
+be exercised locally in RSpec, minimizing the number of cycles you need to go
+through in CI. However, you can speed these cycles up somewhat by emptying the
+`.gitlab/ci/rails.gitlab-ci.yml` file in your merge request. Just don't forget
+to revert the change before merging!
+
+You should add the `~Danger bot` label to the merge request before sending it
+for review.
+
+## Current uses
+
+Here is a (non-exhaustive) list of the kinds of things Danger has been used for
+at GitLab so far:
+
+- Coding style
+- Database review workflow
+- Documentation review workflow
+- Merge request metrics
+- Reviewer roulette workflow
+- Single codebase effort
+
+## Limitations
+
+- [`danger local` does not work on GitLab](https://github.com/danger/danger/issues/458)
+- Danger output is not added to a merge request comment if working on a fork.
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 367a481ee11..157c64b514c 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -38,6 +38,7 @@ A Merge Request author's role is to:
- If database review is needed, add the ~database label.
- Use the [database changes](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/merge_request_templates/Database%20changes.md)
merge request template, or include the appropriate items in the MR description.
+- [Prepare the merge request for a database review](#how-to-prepare-the-merge-request-for-a-database-review).
A database **reviewer**'s role is to:
@@ -68,7 +69,7 @@ make sure you have applied the ~database label and rerun the
`danger-review` CI job, or pick someone from the
[`@gl-database` team](https://gitlab.com/groups/gl-database/-/group_members).
-### How to prepare for speedy database reviews
+### How to prepare the merge request for a database review
In order to make reviewing easier and therefore faster, please consider preparing a comment
and details for a database reviewer:
diff --git a/doc/development/documentation/site_architecture/global_nav.md b/doc/development/documentation/site_architecture/global_nav.md
index 753a636a779..be4d5b5353f 100644
--- a/doc/development/documentation/site_architecture/global_nav.md
+++ b/doc/development/documentation/site_architecture/global_nav.md
@@ -4,30 +4,74 @@ description: "Learn how GitLab docs' global navigation works and how to add new
# Global navigation
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/362)
-in GitLab 11.6.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/362) in GitLab 11.6.
> - [Updated](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/482) in GitLab 12.1.
+> - [Per-project](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/498) navigation added in GitLab 12.2.
-The global nav adds to the left sidebar the ability to
-navigate and explore the contents of GitLab's documentation.
+Global navigation (the left-most pane in our three pane documentation) provides:
-The global nav should be maintained consistent through time to allow the
-users to locate their most-visited links easily to facilitate navigation.
-Therefore, any updates must be carefully considered by the technical writers.
+- A high-level grouped view of product features.
+- The ability to discover new features by browsing the menu structure.
+- A way to allow the reader to focus on product areas.
+- The ability to refine landing pages, so they don't have to do all the work of surfacing
+ every page contained within the documentation.
-## Adding new items to the global nav
+## Adding new items
-To add a new doc to the nav, first and foremost, check with the technical writing team:
+All new pages need a new navigation item. Without a navigation, the page becomes "orphaned". That
+is:
-- If it's applicable
-- What's the exact position the doc will be added to the nav
+- The navigation shuts when the page is opened, and the reader loses their place.
+- The page doesn't belong in a group with other pages.
-Once you get their approval and their guidance in regards to the position on the nav,
-read trhough this page to understand how it works, and submit a merge request to the
-docs site, adding the doc you wish to include in the nav into the
-[global nav data file](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/content/_data/global-nav.yaml).
+This means the decision to create a new page is a decision to create new navigation item and vice
+versa.
-Don't forget to ask a technical writer to review your changes before merging.
+### Where to add
+
+Documentation pages can be said to belong in the following groups:
+
+- GitLab users. This is documentation for day-to-day use of GitLab for users with any level
+ of permissions, from Reporter to Owner.
+- GitLab administrators. This tends to be documentation for self-managed instances that requires
+ access to the underlying infrastructure hosting GitLab.
+- Other documentation. This includes documentation for customers outside their day-to-day use of
+ GitLab and for contributors. Documentation that doesn't fit in the other groups belongs here.
+
+With these groups in mind, the following are general rules for where new items should be added.
+
+- User documentation for:
+ - Group-level features belongs under **Groups**.
+ - Project-level features belongs under **Projects**.
+ - Features outside a group or project level (sometimes called "instance-level") can be placed at
+ the top-level, but care must be taken not to overwhelm that top-level space. If possible, such
+ features could be grouped in some way.
+ - Outside the above, most other miscellaneous user documentation belongs under **User**.
+- Administration documentation belongs under **Administrator**.
+- Other documentation belongs at the top-level, but care must be taken to not create an enormously
+ long top-level navigation, which defeats the purpose of it.
+
+NOTE: **Note:**
+Making all documentation and navigation items adhere to these principles is being progressively
+rolled out.
+
+### What to add
+
+Having decided where to add a navigation element, the next step is deciding what to add. The
+mechanics of what is required is [documented below](#data-file) but, in principle:
+
+- Navigation item text (that which the reader sees) should:
+ - Be as short as possible.
+ - Be contextual. It's rare to need to repeat text from a parent item.
+ - Avoid jargon or terms of art, unless ubiquitous. For example, **CI** is an acceptable
+ substitution for **Continuous Integration**.
+- Navigation links must follow the rules documented in the [data file](#data-file).
+- EE badging is subject to the following:
+ - Required when linking to an EE-only page.
+ - Not required when linking to a page that is a mix of CE and EE-only content.
+ - Required when all sub-items are EE-only. In this case, no sub-items are EE badged.
+ - Not required when sub-items are a mix of CE and EE-only items. In this case, each item is
+ badged appropriately.
## How it works
@@ -55,7 +99,7 @@ To see the improvements planned, check the
[global nav epic](https://gitlab.com/groups/gitlab-com/-/epics/21).
CAUTION: **Attention!**
-**Do not** [add items](#adding-new-items-to-the-global-nav) to the global nav without
+**Do not** [add items](#adding-new-items) to the global nav without
the consent of one of the technical writers.
## Composition
@@ -70,8 +114,13 @@ the data among the nav in containers properly [styled](#css-classes).
### Data file
-The [data file](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/content/_data/global-nav.yaml)
-is structured in three components: sections, categories, and docs.
+The data file describes the structure of the navigation for the applicable project. All data files
+are stored at <https://gitlab.com/gitlab-org/gitlab-docs/blob/master/content/_data/> and comprise
+three components:
+
+- Sections
+- Categories
+- Docs
#### Sections
diff --git a/doc/development/documentation/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md
index 1aef0ed855c..bb598906967 100644
--- a/doc/development/documentation/site_architecture/index.md
+++ b/doc/development/documentation/site_architecture/index.md
@@ -66,10 +66,12 @@ the GitLab Documentation website.
- [Google Analytics](https://marketingplatform.google.com/about/analytics/)
- [Google Tag Manager](https://developers.google.com/tag-manager/)
-## Global nav
+## Global navigation
-To understand how the global nav (left sidebar) is built, please
-read through the [global navigation](global_nav.md) doc.
+Read through the global navigation](global_nav.md) documentation to understand:
+
+- How the global navigation is built.
+- How to add new navigation items.
## Deployment
diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md
index 941eea2609e..10e8008bad3 100644
--- a/doc/development/gotchas.md
+++ b/doc/development/gotchas.md
@@ -18,7 +18,7 @@ end
Consider the following API spec:
```ruby
-require 'rails_helper'
+require 'spec_helper'
describe API::Labels do
it 'creates a first label' do
@@ -69,7 +69,7 @@ is ok, but `create(:label, title: 'label1')` is not.
Following is the fixed API spec:
```ruby
-require 'rails_helper'
+require 'spec_helper'
describe API::Labels do
it 'creates a first label' do
diff --git a/doc/development/integrations/jira_connect.md b/doc/development/integrations/jira_connect.md
index e1350b02262..9ac87a17232 100644
--- a/doc/development/integrations/jira_connect.md
+++ b/doc/development/integrations/jira_connect.md
@@ -10,8 +10,10 @@ The following are required to install and test the app:
For the app to work, Jira Cloud should be able to connect to the GitLab instance through the internet.
- To easily expose your local development environment, you can use tools like [serveo](https://serveo.net) or [ngrok](https://ngrok.com).
- These also take care of SSL for you because Jira requires all connections to the app host to be over SSL.
+ To easily expose your local development environment, you can use tools like
+ [serveo](https://medium.com/@osanda.deshan/how-to-forward-my-local-port-to-public-using-serveo-4979f352a3bf)
+ or [ngrok](https://ngrok.com). These also take care of SSL for you because Jira
+ requires all connections to the app host to be over SSL.
> This feature is currently behind the `:jira_connect_app` feature flag
diff --git a/doc/development/prometheus_metrics.md b/doc/development/prometheus_metrics.md
index 576601372a3..2a34851d21c 100644
--- a/doc/development/prometheus_metrics.md
+++ b/doc/development/prometheus_metrics.md
@@ -44,3 +44,26 @@ class ImportCommonMetrics < ActiveRecord::Migration[4.2]
end
end
```
+
+## GitLab Prometheus metrics
+
+GitLab provides [Prometheus metrics](../administration/monitoring/prometheus/gitlab_metrics.md)
+to monitor itself.
+
+### Adding a new metric
+
+This section describes how to add new metrics for self-monitoring
+([example](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15440)).
+
+1. Select the [type of metric](https://gitlab.com/gitlab-org/prometheus-client-mmap#metrics):
+
+ - `Gitlab::Metrics.counter`
+ - `Gitlab::Metrics.gauge`
+ - `Gitlab::Metrics.histogram`
+ - `Gitlab::Metrics.summary`
+
+1. Select the appropriate name for your metric. Refer to the guidelines
+ for [Prometheus metric names](https://prometheus.io/docs/practices/naming/#metric-names).
+1. Update the list of [GitLab Prometheus metrics](../administration/monitoring/prometheus/gitlab_metrics.md).
+1. Trigger the relevant page/code that will record the new metric.
+1. Check that the new metric appears at `/-/metrics`.
diff --git a/doc/development/testing_guide/end_to_end/best_practices.md b/doc/development/testing_guide/end_to_end/best_practices.md
index 89500ef9a90..2200069ecfd 100644
--- a/doc/development/testing_guide/end_to_end/best_practices.md
+++ b/doc/development/testing_guide/end_to_end/best_practices.md
@@ -1,5 +1,7 @@
# Best practices when writing end-to-end tests
+## Avoid using a GUI when it's not required
+
The majority of the end-to-end tests require some state to be built in the application for the tests to happen.
A good example is a user being logged in as a pre-condition for testing the feature.
@@ -36,3 +38,18 @@ Finally, interacting with the application only by its GUI generates a higher rat
- When depending only on the GUI to create the application's state and tests fail due to front-end issues, we can't rely on the test failures rate, and we generate a higher rate of test flakiness.
Now that we are aware of all of it, [let's go create some tests](quick_start_guide.md).
+
+## Prefer to split tests across multiple files
+
+Our framework includes a couple of parallelization mechanisms that work by executing spec files in parallel.
+
+However, because tests are parallelized by spec *file* and not by test/example, we can't achieve greater parallelization if a new test is added to an existing file.
+
+Nonetheless, there could be other reasons to add a new test to an existing file.
+
+For example, if tests share state that is expensive to set up it might be more efficient to perform that setup once even if it means the tests that use the setup can't be parallelized.
+
+In summary:
+
+- **Do**: Split tests across separate files, unless the tests share expensive setup.
+- **Don't**: Put new tests in an existing file without considering the impact on parallelization.
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 3ae3ce183d9..f6a2f642274 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -118,7 +118,7 @@ Helm chart][helm-chart], itself deployed with custom
See [Review Apps][review-apps] for more details about Review Apps.
-[helm-chart]: https://gitlab.com/charts/gitlab/
+[helm-chart]: https://gitlab.com/gitlab-org/charts/gitlab/
[cng]: https://gitlab.com/gitlab-org/build/CNG
## How do I run the tests?
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index 28a60660995..13772cbe015 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -267,7 +267,7 @@ find a way to limit it to only us.**
- [Review Apps integration for CE/EE (presentation)](https://docs.google.com/presentation/d/1QPLr6FO4LduROU8pQIPkX1yfGvD13GEJIBOenqoKxR8/edit?usp=sharing)
-[charts-1068]: https://gitlab.com/charts/gitlab/issues/1068
+[charts-1068]: https://gitlab.com/gitlab-org/charts/gitlab/issues/1068
[gitlab-pipeline]: https://gitlab.com/gitlab-org/gitlab-ce/pipelines/44362587
[gitlab:assets:compile]: https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/149511610
[review-build-cng]: https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/149511623
@@ -276,7 +276,7 @@ find a way to limit it to only us.**
[cng]: https://gitlab.com/gitlab-org/build/CNG
[cng-mirror-pipeline]: https://gitlab.com/gitlab-org/build/CNG-mirror/pipelines/44364657
[cng-mirror-registry]: https://gitlab.com/gitlab-org/build/CNG-mirror/container_registry
-[helm-chart]: https://gitlab.com/charts/gitlab/
+[helm-chart]: https://gitlab.com/gitlab-org/charts/gitlab/
[review-apps-ce]: https://console.cloud.google.com/kubernetes/clusters/details/us-central1-a/review-apps-ce?project=gitlab-review-apps
[review-apps-ee]: https://console.cloud.google.com/kubernetes/clusters/details/us-central1-b/review-apps-ee?project=gitlab-review-apps
[review-apps.sh]: https://gitlab.com/gitlab-org/gitlab-ee/blob/master/scripts/review_apps/review-apps.sh
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 336000f6cb9..59b775d13bd 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -92,9 +92,9 @@ If you are running GitLab within a Docker container, you can run the backup from
docker exec -t <container name> gitlab-backup create
```
-If you are using the [GitLab helm chart](https://gitlab.com/charts/gitlab) on a
+If you are using the [GitLab helm chart](https://gitlab.com/gitlab-org/charts/gitlab) on a
Kubernetes cluster, you can run the backup task using `backup-utility` script on
-the GitLab task runner pod via `kubectl`. Refer to [backing up a GitLab installation](https://gitlab.com/charts/gitlab/blob/master/doc/backup-restore/backup.md#backing-up-a-gitlab-installation) for more details:
+the GitLab task runner pod via `kubectl`. Refer to [backing up a GitLab installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/backup.md#backing-up-a-gitlab-installation) for more details:
```sh
kubectl exec -it <gitlab task-runner pod> backup-utility
@@ -764,7 +764,7 @@ docker exec -it <name of container> gitlab-backup restore
```
The GitLab helm chart uses a different process, documented in
-[restoring a GitLab helm chart installation](https://gitlab.com/charts/gitlab/blob/master/doc/backup-restore/restore.md).
+[restoring a GitLab helm chart installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/restore.md).
## Alternative backup strategies
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index 1e9eb15533a..24a334e7067 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -13,6 +13,7 @@ Your GitLab instance can perform HTTP POST requests on the following events:
- `project_update`
- `user_add_to_team`
- `user_remove_from_team`
+- `user_update_for_team`
- `user_create`
- `user_destroy`
- `user_failed_login`
@@ -24,6 +25,7 @@ Your GitLab instance can perform HTTP POST requests on the following events:
- `group_rename`
- `user_add_to_group`
- `user_remove_from_group`
+- `user_update_for_group`
The triggers for most of these are self-explanatory, but `project_update` and `project_rename` deserve some clarification: `project_update` is fired any time an attribute of a project is changed (name, description, tags, etc.) *unless* the `path` attribute is also changed. In that case, a `project_rename` is triggered instead (so that, for instance, if all you care about is the repo URL, you can just listen for `project_rename`).
@@ -173,6 +175,26 @@ Please refer to `group_rename` and `user_rename` for that case.
}
```
+**Team Member Updated:**
+
+```json
+{
+ "created_at": "2012-07-21T07:30:56Z",
+ "updated_at": "2012-07-21T07:38:22Z",
+ "event_name": "user_update_for_team",
+ "access_level": "Maintainer",
+ "project_id": 74,
+ "project_name": "StoreCloud",
+ "project_path": "storecloud",
+ "project_path_with_namespace": "jsmith/storecloud",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
+ "user_username": "johnsmith",
+ "user_id": 41,
+ "project_visibility": "visibilitylevel|private"
+}
+```
+
**User created:**
```json
@@ -349,6 +371,24 @@ If the user is blocked via LDAP, `state` will be `ldap_blocked`.
}
```
+**Group Member Updated:**
+
+```json
+{
+ "created_at": "2012-07-21T07:30:56Z",
+ "updated_at": "2012-07-21T07:38:22Z",
+ "event_name": "user_update_for_group",
+ "group_access": "Maintainer",
+ "group_id": 78,
+ "group_name": "StoreCloud",
+ "group_path": "storecloud",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
+ "user_username": "johnsmith",
+ "user_id": 41
+}
+```
+
## Push events
Triggered when you push to the repository, except when pushing tags.
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index a030f8d96ef..c3f80c6a0fd 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -127,7 +127,7 @@ build:
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups and projects. Read more about the
+vulnerabilities in your groups, projects and pipelines. Read more about the
[Security Dashboard](../security_dashboard/index.md).
## Interacting with the vulnerabilities
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index fa84f995e58..2d9f522c4f0 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -84,6 +84,8 @@ There are two ways to define the URL to be scanned by DAST:
- Set the `DAST_WEBSITE` [variable](../../../ci/yaml/README.md#variables).
- Add it in an `environment_url.txt` file at the root of your project.
+If both values are set, the `DAST_WEBSITE` value will take precedence.
+
The included template will create a `dast` job in your CI/CD pipeline and scan
your project's source code for possible vulnerabilities.
@@ -134,7 +136,7 @@ variables:
The DAST settings can be changed through environment variables by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
-These variables are documented in the [DAST README](https://gitlab.com/gitlab-org/security-products/dast#settings).
+These variables are documented in [available variables](#available-variables).
For example:
@@ -196,7 +198,7 @@ variable value.
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups and projects. Read more about the
+vulnerabilities in your groups, projects and pipelines. Read more about the
[Security Dashboard](../security_dashboard/index.md).
## Interacting with the vulnerabilities
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index b40392e12d5..fa2df667031 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -77,7 +77,7 @@ like Gemnasium require sending data to GitLab central servers to analyze them:
The Gemnasium client does **NOT** send the exact package versions your project relies on.
You can disable the remote checks by [using](#customizing-the-dependency-scanning-settings)
-the `DS_DISABLE_REMOTE_CHECKS` environment variable and setting it to `true`.
+the `DS_DISABLE_REMOTE_CHECKS` environment variable and setting it to `"true"`.
## Configuration
@@ -115,7 +115,7 @@ include:
template: Dependency-Scanning.gitlab-ci.yml
variables:
- DS_DISABLE_REMOTE_CHECKS: true
+ DS_DISABLE_REMOTE_CHECKS: "true"
```
Because template is [evaluated before](../../../ci/yaml/README.md#include) the pipeline
@@ -314,7 +314,7 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups and projects. Read more about the
+vulnerabilities in your groups, projects and pipelines. Read more about the
[Security Dashboard](../security_dashboard/index.md).
## Interacting with the vulnerabilities
diff --git a/doc/user/application_security/sast/img/security_report.png b/doc/user/application_security/sast/img/security_report.png
deleted file mode 100644
index ba41b707238..00000000000
--- a/doc/user/application_security/sast/img/security_report.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 5e7bc4142fb..fbc130689e0 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -333,20 +333,10 @@ CI/CD configuration file to turn it on. Results are available in the SAST report
GitLab currently includes [Gitleaks](https://github.com/zricethezav/gitleaks) and [TruffleHog](https://github.com/dxa4481/truffleHog) checks.
-## Security report under pipelines
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/3776)
-in [GitLab Ultimate](https://about.gitlab.com/pricing) 10.6.
-
-Visit any pipeline page which has a `sast` job and you will be able to see
-the security report tab with the listed vulnerabilities (if any).
-
-![Security Report](img/security_report.png)
-
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups and projects. Read more about the
+vulnerabilities in your groups, projects and pipelines. Read more about the
[Security Dashboard](../security_dashboard/index.md).
## Interacting with the vulnerabilities
diff --git a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.png b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.png
index 61f683c1335..1fe76a9e08f 100644..100755
--- a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.png
+++ b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/pipeline_security_dashboard_v12_3.png b/doc/user/application_security/security_dashboard/img/pipeline_security_dashboard_v12_3.png
new file mode 100755
index 00000000000..09979ba99b3
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/pipeline_security_dashboard_v12_3.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard.png
deleted file mode 100644
index baa136fd885..00000000000
--- a/doc/user/application_security/security_dashboard/img/project_security_dashboard.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.png
new file mode 100755
index 00000000000..51e80bdb50d
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index e7cda35eb98..ac539509e22 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -5,7 +5,7 @@ type: reference, howto
# GitLab Security Dashboard **(ULTIMATE)**
The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups and projects.
+vulnerabilities in your groups, projects and pipelines.
You can also drill down into a vulnerability and get extra information, see which
project it comes from, the file it's in, and various metadata to help you analyze
@@ -26,7 +26,7 @@ The Security Dashboard supports the following reports:
## Requirements
-To use the project or group security dashboard:
+To use the group, project or pipeline security dashboard:
1. At least one project inside a group must be configured with at least one of
the [supported reports](#supported-reports).
@@ -34,6 +34,16 @@ To use the project or group security dashboard:
1. [GitLab Runner](https://docs.gitlab.com/runner/) 11.5 or newer must be used.
If you're using the shared Runners on GitLab.com, this is already the case.
+## Pipeline Security Dashboard
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/13496) in [GitLab Ultimate](https://about.gitlab.com/pricing) 12.3.
+
+At the pipeline level, the Security Dashboard displays the vulnerabilities present in the branch of the project the pipeline was run against.
+
+Visit the page for any pipeline which has run any of the [supported reports](#supported-reports). Click the **Security** tab to view the Security Dashboard.
+
+![Pipeline Security Dashboard](img/pipeline_security_dashboard_v12_3.png)
+
## Project Security Dashboard
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6165) in [GitLab Ultimate](https://about.gitlab.com/pricing) 11.1.
@@ -42,12 +52,11 @@ At the project level, the Security Dashboard displays the latest security report
for your project. Use it to find and fix vulnerabilities affecting the
[default branch](../../project/repository/branches/index.md#default-branch).
-![Project Security Dashboard](img/project_security_dashboard.png)
+![Project Security Dashboard](img/project_security_dashboard_v12_3.png)
## Group Security Dashboard
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6709) in
-> [GitLab Ultimate](https://about.gitlab.com/pricing) 11.5.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6709) in [GitLab Ultimate](https://about.gitlab.com/pricing) 11.5.
The group Security Dashboard gives an overview of the vulnerabilities of all the
projects in a group and its subgroups.
@@ -62,12 +71,15 @@ Once you're on the dashboard, at the top you should see a series of filters for:
- Report type
- Project
+To the right of the filters, you should see a **Hide dismissed** toggle button.
+
NOTE: **Note:**
The dashboard only shows projects with [security reports](#supported-reports) enabled in a group.
![dashboard with action buttons and metrics](img/group_security_dashboard_v12_3.png)
-Selecting one or more filters will filter the results in this page.
+Selecting one or more filters will filter the results in this page. Disabling the **Hide dismissed**
+toggle button will let you also see vulnerabilities that have been dismissed.
The main section is a list of all the vulnerabilities in the group, sorted by severity.
In that list, you can see the severity of the vulnerability, its name, its
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 86fb7533e70..c09acd36e31 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -443,6 +443,12 @@ A group owner can check the aggregated storage usage for all the project in a gr
![Group storage usage quota](img/group_storage_usage_quota.png)
+The total usage of the storage is updated if any relevant event that
+will affect its value is triggered (e.g., a commit push).
+For performance reasons, we may delay the update up to 1 hour and 30 minutes.
+
+If your namespace shows `N/A` as the total storage usage, you can trigger a recalculation by pushing a commit to any project in that namespace.
+
## User contribution analysis **(STARTER)**
With [GitLab Contribution Analytics](contribution_analytics/index.md),
diff --git a/doc/user/instance/clusters/index.md b/doc/user/instance/clusters/index.md
index f557dcf4b3c..cb1bfc69826 100644
--- a/doc/user/instance/clusters/index.md
+++ b/doc/user/instance/clusters/index.md
@@ -19,4 +19,4 @@ GitLab will try match to clusters in the following order:
- Instance level
To be selected, the cluster must be enabled and
-match the [environment selector](../../../ci/environments.md#scoping-environments-with-specs-premium).
+match the [environment selector](../../../ci/environments.md#scoping-environments-with-specs).
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index c28a5e49ec4..02b5f7437ee 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -37,6 +37,8 @@ usernames. A GitLab administrator can configure the GitLab instance to
NOTE: **Note:**
In GitLab 11.0, the Master role was renamed to Maintainer.
+While Maintainer is the highest project-level role, some actions can only be performed by a personal namespace or group owner.
+
The following table depicts the various user permission levels in a project.
| Action | Guest | Reporter | Developer |Maintainer| Owner |
@@ -74,7 +76,7 @@ The following table depicts the various user permission levels in a project.
| View project statistics | | ✓ | ✓ | ✓ | ✓ |
| View Error Tracking list | | ✓ | ✓ | ✓ | ✓ |
| Pull from [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ |
-| Publish to [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **(PREMIUM)** | | | ✓ | ✓ | ✓ ||
+| Publish to [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Upload [Design Management](project/issues/design_management.md) files **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Create new branches | | | ✓ | ✓ | ✓ |
| Push to non-protected branches | | | ✓ | ✓ | ✓ |
diff --git a/doc/user/project/import/gemnasium.md b/doc/user/project/import/gemnasium.md
index cf48189fa6e..3217bbc4772 100644
--- a/doc/user/project/import/gemnasium.md
+++ b/doc/user/project/import/gemnasium.md
@@ -98,7 +98,7 @@ back to both GitLab and GitHub when completed.
1. The result of the job will be visible directly from the pipeline view:
- ![security report](img/gemnasium/report.png)
+ ![Security Dashboard](../../application_security/security_dashboard/img/pipeline_security_dashboard_v12_3.png)
NOTE: **Note:**
If you don't commit very often to your project, you may want to use
diff --git a/doc/user/project/import/img/gemnasium/report.png b/doc/user/project/import/img/gemnasium/report.png
deleted file mode 100644
index 5c4d58662c0..00000000000
--- a/doc/user/project/import/img/gemnasium/report.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md
index 6536a1a0a4b..39ca1bd0c77 100644
--- a/doc/user/project/operations/feature_flags.md
+++ b/doc/user/project/operations/feature_flags.md
@@ -2,10 +2,6 @@
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11845) in GitLab 11.4.
-CAUTION: **Warning:**
-This an _alpha_ feature and is subject to change at any time without
-prior notice.
-
Feature flags allow you to ship a project in different flavors by
dynamically toggling certain functionality.
@@ -67,15 +63,15 @@ For example, you may not want to enable a feature flag on production until your
first confirmed that the feature is working correctly on testing environments.
To handle these situations, you can enable a feature flag on a particular environment
-with [Environment specs](../../../ci/environments.md#scoping-environments-with-specs-premium).
+with [Environment specs](../../../ci/environments.md#scoping-environments-with-specs).
You can define multiple specs per flag so that you can control your feature flag more granularly.
To define specs for each environment:
1. Navigate to your project's **Operations > Feature Flags**.
1. Click on the **New Feature Flag** button or edit an existing flag.
-1. Set the status of the default [spec](../../../ci/environments.md#scoping-environments-with-specs-premium) (`*`). Choose a rollout strategy. This status and rollout strategy combination will be used for _all_ environments.
-1. If you want to enable/disable the feature on a specific environment, create a new [spec](../../../ci/environments.md#scoping-environments-with-specs-premium) and type the environment name.
+1. Set the status of the default [spec](../../../ci/environments.md#scoping-environments-with-specs) (`*`). Choose a rollout strategy. This status and rollout strategy combination will be used for _all_ environments.
+1. If you want to enable/disable the feature on a specific environment, create a new [spec](../../../ci/environments.md#scoping-environments-with-specs) and type the environment name.
1. Set the status and rollout strategy of the additional spec. This status and rollout strategy combination takes precedence over the default spec since we always use the most specific match available.
1. Click **Create feature flag** or **Update feature flag**.
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index e373d605098..1f7f85e9750 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -14,8 +14,11 @@ on a separate line in order to be properly detected and executed. Once executed,
## Quick Actions for issues, merge requests and epics
-The following quick actions are applicable to descriptions, discussions and threads
-in issues and merge requests, as well as epics.**(ULTIMATE)**
+The following quick actions are applicable to descriptions, discussions and threads in:
+
+- Issues
+- Merge requests
+- Epics **(ULTIMATE)**
| Command | Issue | Merge request | Epic | Action |
|:--------------------------------------|:------|:--------------|:-----|:------ |
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 219ed45eff6..aa6a67d817a 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -118,7 +118,7 @@ module API
mount ::API::GroupContainerRepositories
mount ::API::GroupVariables
mount ::API::ImportGithub
- mount ::API::Internal
+ mount ::API::Internal::Base
mount ::API::Issues
mount ::API::JobArtifacts
mount ::API::Jobs
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index cfcf6228225..f7cd6d35854 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -978,7 +978,9 @@ module API
expose :created_at
def todo_target_class(target_type)
- ::API::Entities.const_get(target_type)
+ # false as second argument prevents looking up in module hierarchy
+ # see also https://gitlab.com/gitlab-org/gitlab-ce/issues/59719
+ ::API::Entities.const_get(target_type, false)
end
end
@@ -1229,6 +1231,7 @@ module API
expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
expose :commit, using: Entities::Commit, if: lambda { |_, _| can_download_code? }
expose :upcoming_release?, as: :upcoming_release
+ expose :milestone, using: Entities::Milestone, if: -> (release, _) { release.milestone.present? }
expose :assets do
expose :assets_count, as: :count do |release, _|
@@ -1730,6 +1733,7 @@ API::Entities.prepend_if_ee('EE::API::Entities::Entities')
::API::Entities::Group.prepend_if_ee('EE::API::Entities::Group', with_descendants: true)
::API::Entities::GroupDetail.prepend_if_ee('EE::API::Entities::GroupDetail')
::API::Entities::IssueBasic.prepend_if_ee('EE::API::Entities::IssueBasic', with_descendants: true)
+::API::Entities::Issue.prepend_if_ee('EE::API::Entities::Issue')
::API::Entities::List.prepend_if_ee('EE::API::Entities::List')
::API::Entities::MergeRequestBasic.prepend_if_ee('EE::API::Entities::MergeRequestBasic', with_descendants: true)
::API::Entities::Namespace.prepend_if_ee('EE::API::Entities::Namespace')
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 0bcd09d3977..0b086f2e36d 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -75,6 +75,7 @@ module API
).execute
projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled]
projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled]
+ projects = projects.visible_to_user_and_access_level(current_user, params[:min_access_level]) if params[:min_access_level]
projects = reorder_projects(projects)
paginate(projects)
end
@@ -213,6 +214,7 @@ module API
optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature'
optional :with_shared, type: Boolean, default: true, desc: 'Include projects shared to this group'
optional :include_subgroups, type: Boolean, default: false, desc: 'Includes projects in subgroups of this group'
+ optional :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Limit by minimum access level of authenticated user on projects'
use :pagination
use :with_custom_attributes
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
deleted file mode 100644
index 088ea5bd79a..00000000000
--- a/lib/api/internal.rb
+++ /dev/null
@@ -1,294 +0,0 @@
-# frozen_string_literal: true
-
-module API
- # Internal access API
- class Internal < Grape::API
- before { authenticate_by_gitlab_shell_token! }
-
- helpers ::API::Helpers::InternalHelpers
- helpers ::Gitlab::Identifier
-
- UNKNOWN_CHECK_RESULT_ERROR = 'Unknown check result'.freeze
-
- helpers do
- def response_with_status(code: 200, success: true, message: nil, **extra_options)
- status code
- { status: success, message: message }.merge(extra_options).compact
- end
-
- def lfs_authentication_url(project)
- # This is a separate method so that EE can alter its behaviour more
- # easily.
- project.http_url_to_repo
- end
- end
-
- namespace 'internal' do
- # Check if git command is allowed for project
- #
- # Params:
- # key_id - ssh key id for Git over SSH
- # user_id - user id for Git over HTTP or over SSH in keyless SSH CERT mode
- # username - user name for Git over SSH in keyless SSH cert mode
- # protocol - Git access protocol being used, e.g. HTTP or SSH
- # project - project full_path (not path on disk)
- # action - git action (git-upload-pack or git-receive-pack)
- # changes - changes as "oldrev newrev ref", see Gitlab::ChangesList
- # rubocop: disable CodeReuse/ActiveRecord
- post "/allowed" do
- # Stores some Git-specific env thread-safely
- env = parse_env
- Gitlab::Git::HookEnv.set(gl_repository, env) if project
-
- actor =
- if params[:key_id]
- Key.find_by(id: params[:key_id])
- elsif params[:user_id]
- User.find_by(id: params[:user_id])
- elsif params[:username]
- UserFinder.new(params[:username]).find_by_username
- end
-
- protocol = params[:protocol]
-
- actor.update_last_used_at if actor.is_a?(Key)
- user =
- if actor.is_a?(Key)
- actor.user
- else
- actor
- end
-
- access_checker_klass = repo_type.access_checker_class
- access_checker = access_checker_klass.new(actor, project,
- protocol, authentication_abilities: ssh_authentication_abilities,
- namespace_path: namespace_path, project_path: project_path,
- redirected_path: redirected_path)
-
- check_result = begin
- result = access_checker.check(params[:action], params[:changes])
- @project ||= access_checker.project
- result
- rescue Gitlab::GitAccess::UnauthorizedError => e
- break response_with_status(code: 401, success: false, message: e.message)
- rescue Gitlab::GitAccess::TimeoutError => e
- break response_with_status(code: 503, success: false, message: e.message)
- rescue Gitlab::GitAccess::NotFoundError => e
- break response_with_status(code: 404, success: false, message: e.message)
- end
-
- log_user_activity(actor)
-
- case check_result
- when ::Gitlab::GitAccessResult::Success
- payload = {
- gl_repository: gl_repository,
- gl_project_path: gl_project_path,
- gl_id: Gitlab::GlId.gl_id(user),
- gl_username: user&.username,
- git_config_options: [],
- gitaly: gitaly_payload(params[:action]),
- gl_console_messages: check_result.console_messages
- }
-
- # Custom option for git-receive-pack command
- receive_max_input_size = Gitlab::CurrentSettings.receive_max_input_size.to_i
- if receive_max_input_size > 0
- payload[:git_config_options] << "receive.maxInputSize=#{receive_max_input_size.megabytes}"
- end
-
- response_with_status(**payload)
- when ::Gitlab::GitAccessResult::CustomAction
- response_with_status(code: 300, message: check_result.message, payload: check_result.payload)
- else
- response_with_status(code: 500, success: false, message: UNKNOWN_CHECK_RESULT_ERROR)
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- # rubocop: disable CodeReuse/ActiveRecord
- post "/lfs_authenticate" do
- status 200
-
- if params[:key_id]
- actor = Key.find(params[:key_id])
- actor.update_last_used_at
- elsif params[:user_id]
- actor = User.find_by(id: params[:user_id])
- raise ActiveRecord::RecordNotFound.new("No such user id!") unless actor
- else
- raise ActiveRecord::RecordNotFound.new("No key_id or user_id passed!")
- end
-
- Gitlab::LfsToken
- .new(actor)
- .authentication_payload(lfs_authentication_url(project))
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- get "/merge_request_urls" do
- merge_request_urls
- end
-
- #
- # Get a ssh key using the fingerprint
- #
- # rubocop: disable CodeReuse/ActiveRecord
- get "/authorized_keys" do
- fingerprint = params.fetch(:fingerprint) do
- Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
- end
- key = Key.find_by(fingerprint: fingerprint)
- not_found!("Key") if key.nil?
- present key, with: Entities::SSHKey
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- #
- # Discover user by ssh key, user id or username
- #
- # rubocop: disable CodeReuse/ActiveRecord
- get "/discover" do
- if params[:key_id]
- key = Key.find(params[:key_id])
- user = key.user
- elsif params[:user_id]
- user = User.find_by(id: params[:user_id])
- elsif params[:username]
- user = UserFinder.new(params[:username]).find_by_username
- end
-
- present user, with: Entities::UserSafe
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- get "/check" do
- {
- api_version: API.version,
- gitlab_version: Gitlab::VERSION,
- gitlab_rev: Gitlab.revision,
- redis: redis_ping
- }
- end
-
- get "/broadcast_messages" do
- if messages = BroadcastMessage.current
- present messages, with: Entities::BroadcastMessage
- else
- []
- end
- end
-
- get "/broadcast_message" do
- if message = BroadcastMessage.current&.last
- present message, with: Entities::BroadcastMessage
- else
- {}
- end
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- post '/two_factor_recovery_codes' do
- status 200
-
- if params[:key_id]
- key = Key.find_by(id: params[:key_id])
-
- if key
- key.update_last_used_at
- else
- break { 'success' => false, 'message' => 'Could not find the given key' }
- end
-
- if key.is_a?(DeployKey)
- break { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' }
- end
-
- user = key.user
-
- unless user
- break { success: false, message: 'Could not find a user for the given key' }
- end
- elsif params[:user_id]
- user = User.find_by(id: params[:user_id])
-
- unless user
- break { success: false, message: 'Could not find the given user' }
- end
- end
-
- unless user.two_factor_enabled?
- break { success: false, message: 'Two-factor authentication is not enabled for this user' }
- end
-
- codes = nil
-
- ::Users::UpdateService.new(current_user, user: user).execute! do |user|
- codes = user.generate_otp_backup_codes!
- end
-
- { success: true, recovery_codes: codes }
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- post '/pre_receive' do
- status 200
-
- reference_counter_increased = Gitlab::ReferenceCounter.new(params[:gl_repository]).increase
-
- { reference_counter_increased: reference_counter_increased }
- end
-
- post "/notify_post_receive" do
- status 200
-
- # TODO: Re-enable when Gitaly is processing the post-receive notification
- # return unless Gitlab::GitalyClient.enabled?
- #
- # begin
- # repository = wiki? ? project.wiki.repository : project.repository
- # Gitlab::GitalyClient::NotificationService.new(repository.raw_repository).post_receive
- # rescue GRPC::Unavailable => e
- # render_api_error!(e, 500)
- # end
- end
-
- post '/post_receive' do
- status 200
-
- response = Gitlab::InternalPostReceive::Response.new
- user = identify(params[:identifier])
- project = Gitlab::GlRepository.parse(params[:gl_repository]).first
- push_options = Gitlab::PushOptions.new(params[:push_options])
-
- response.reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease
-
- PostReceive.perform_async(params[:gl_repository], params[:identifier],
- params[:changes], push_options.as_json)
-
- mr_options = push_options.get(:merge_request)
- if mr_options.present?
- message = process_mr_push_options(mr_options, project, user, params[:changes])
- response.add_alert_message(message)
- end
-
- broadcast_message = BroadcastMessage.current&.last&.message
- response.add_alert_message(broadcast_message)
-
- response.add_merge_request_urls(merge_request_urls)
-
- # A user is not guaranteed to be returned; an orphaned write deploy
- # key could be used
- if user
- redirect_message = Gitlab::Checks::ProjectMoved.fetch_message(user.id, project.id)
- project_created_message = Gitlab::Checks::ProjectCreated.fetch_message(user.id, project.id)
-
- response.add_basic_message(redirect_message)
- response.add_basic_message(project_created_message)
- end
-
- present response, with: Entities::InternalPostReceive::Response
- end
- end
- end
-end
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
new file mode 100644
index 00000000000..622032b8355
--- /dev/null
+++ b/lib/api/internal/base.rb
@@ -0,0 +1,296 @@
+# frozen_string_literal: true
+
+module API
+ # Internal access API
+ module Internal
+ class Base < Grape::API
+ before { authenticate_by_gitlab_shell_token! }
+
+ helpers ::API::Helpers::InternalHelpers
+ helpers ::Gitlab::Identifier
+
+ UNKNOWN_CHECK_RESULT_ERROR = 'Unknown check result'.freeze
+
+ helpers do
+ def response_with_status(code: 200, success: true, message: nil, **extra_options)
+ status code
+ { status: success, message: message }.merge(extra_options).compact
+ end
+
+ def lfs_authentication_url(project)
+ # This is a separate method so that EE can alter its behaviour more
+ # easily.
+ project.http_url_to_repo
+ end
+ end
+
+ namespace 'internal' do
+ # Check if git command is allowed for project
+ #
+ # Params:
+ # key_id - ssh key id for Git over SSH
+ # user_id - user id for Git over HTTP or over SSH in keyless SSH CERT mode
+ # username - user name for Git over SSH in keyless SSH cert mode
+ # protocol - Git access protocol being used, e.g. HTTP or SSH
+ # project - project full_path (not path on disk)
+ # action - git action (git-upload-pack or git-receive-pack)
+ # changes - changes as "oldrev newrev ref", see Gitlab::ChangesList
+ # rubocop: disable CodeReuse/ActiveRecord
+ post "/allowed" do
+ # Stores some Git-specific env thread-safely
+ env = parse_env
+ Gitlab::Git::HookEnv.set(gl_repository, env) if project
+
+ actor =
+ if params[:key_id]
+ Key.find_by(id: params[:key_id])
+ elsif params[:user_id]
+ User.find_by(id: params[:user_id])
+ elsif params[:username]
+ UserFinder.new(params[:username]).find_by_username
+ end
+
+ protocol = params[:protocol]
+
+ actor.update_last_used_at if actor.is_a?(Key)
+ user =
+ if actor.is_a?(Key)
+ actor.user
+ else
+ actor
+ end
+
+ access_checker_klass = repo_type.access_checker_class
+ access_checker = access_checker_klass.new(actor, project,
+ protocol, authentication_abilities: ssh_authentication_abilities,
+ namespace_path: namespace_path, project_path: project_path,
+ redirected_path: redirected_path)
+
+ check_result = begin
+ result = access_checker.check(params[:action], params[:changes])
+ @project ||= access_checker.project
+ result
+ rescue Gitlab::GitAccess::UnauthorizedError => e
+ break response_with_status(code: 401, success: false, message: e.message)
+ rescue Gitlab::GitAccess::TimeoutError => e
+ break response_with_status(code: 503, success: false, message: e.message)
+ rescue Gitlab::GitAccess::NotFoundError => e
+ break response_with_status(code: 404, success: false, message: e.message)
+ end
+
+ log_user_activity(actor)
+
+ case check_result
+ when ::Gitlab::GitAccessResult::Success
+ payload = {
+ gl_repository: gl_repository,
+ gl_project_path: gl_project_path,
+ gl_id: Gitlab::GlId.gl_id(user),
+ gl_username: user&.username,
+ git_config_options: [],
+ gitaly: gitaly_payload(params[:action]),
+ gl_console_messages: check_result.console_messages
+ }
+
+ # Custom option for git-receive-pack command
+ receive_max_input_size = Gitlab::CurrentSettings.receive_max_input_size.to_i
+ if receive_max_input_size > 0
+ payload[:git_config_options] << "receive.maxInputSize=#{receive_max_input_size.megabytes}"
+ end
+
+ response_with_status(**payload)
+ when ::Gitlab::GitAccessResult::CustomAction
+ response_with_status(code: 300, message: check_result.message, payload: check_result.payload)
+ else
+ response_with_status(code: 500, success: false, message: UNKNOWN_CHECK_RESULT_ERROR)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ post "/lfs_authenticate" do
+ status 200
+
+ if params[:key_id]
+ actor = Key.find(params[:key_id])
+ actor.update_last_used_at
+ elsif params[:user_id]
+ actor = User.find_by(id: params[:user_id])
+ raise ActiveRecord::RecordNotFound.new("No such user id!") unless actor
+ else
+ raise ActiveRecord::RecordNotFound.new("No key_id or user_id passed!")
+ end
+
+ Gitlab::LfsToken
+ .new(actor)
+ .authentication_payload(lfs_authentication_url(project))
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ get "/merge_request_urls" do
+ merge_request_urls
+ end
+
+ #
+ # Get a ssh key using the fingerprint
+ #
+ # rubocop: disable CodeReuse/ActiveRecord
+ get "/authorized_keys" do
+ fingerprint = params.fetch(:fingerprint) do
+ Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
+ end
+ key = Key.find_by(fingerprint: fingerprint)
+ not_found!("Key") if key.nil?
+ present key, with: Entities::SSHKey
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ #
+ # Discover user by ssh key, user id or username
+ #
+ # rubocop: disable CodeReuse/ActiveRecord
+ get "/discover" do
+ if params[:key_id]
+ key = Key.find(params[:key_id])
+ user = key.user
+ elsif params[:user_id]
+ user = User.find_by(id: params[:user_id])
+ elsif params[:username]
+ user = UserFinder.new(params[:username]).find_by_username
+ end
+
+ present user, with: Entities::UserSafe
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ get "/check" do
+ {
+ api_version: API.version,
+ gitlab_version: Gitlab::VERSION,
+ gitlab_rev: Gitlab.revision,
+ redis: redis_ping
+ }
+ end
+
+ get "/broadcast_messages" do
+ if messages = BroadcastMessage.current
+ present messages, with: Entities::BroadcastMessage
+ else
+ []
+ end
+ end
+
+ get "/broadcast_message" do
+ if message = BroadcastMessage.current&.last
+ present message, with: Entities::BroadcastMessage
+ else
+ {}
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ post '/two_factor_recovery_codes' do
+ status 200
+
+ if params[:key_id]
+ key = Key.find_by(id: params[:key_id])
+
+ if key
+ key.update_last_used_at
+ else
+ break { 'success' => false, 'message' => 'Could not find the given key' }
+ end
+
+ if key.is_a?(DeployKey)
+ break { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' }
+ end
+
+ user = key.user
+
+ unless user
+ break { success: false, message: 'Could not find a user for the given key' }
+ end
+ elsif params[:user_id]
+ user = User.find_by(id: params[:user_id])
+
+ unless user
+ break { success: false, message: 'Could not find the given user' }
+ end
+ end
+
+ unless user.two_factor_enabled?
+ break { success: false, message: 'Two-factor authentication is not enabled for this user' }
+ end
+
+ codes = nil
+
+ ::Users::UpdateService.new(current_user, user: user).execute! do |user|
+ codes = user.generate_otp_backup_codes!
+ end
+
+ { success: true, recovery_codes: codes }
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ post '/pre_receive' do
+ status 200
+
+ reference_counter_increased = Gitlab::ReferenceCounter.new(params[:gl_repository]).increase
+
+ { reference_counter_increased: reference_counter_increased }
+ end
+
+ post "/notify_post_receive" do
+ status 200
+
+ # TODO: Re-enable when Gitaly is processing the post-receive notification
+ # return unless Gitlab::GitalyClient.enabled?
+ #
+ # begin
+ # repository = wiki? ? project.wiki.repository : project.repository
+ # Gitlab::GitalyClient::NotificationService.new(repository.raw_repository).post_receive
+ # rescue GRPC::Unavailable => e
+ # render_api_error!(e, 500)
+ # end
+ end
+
+ post '/post_receive' do
+ status 200
+
+ response = Gitlab::InternalPostReceive::Response.new
+ user = identify(params[:identifier])
+ project = Gitlab::GlRepository.parse(params[:gl_repository]).first
+ push_options = Gitlab::PushOptions.new(params[:push_options])
+
+ response.reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease
+
+ PostReceive.perform_async(params[:gl_repository], params[:identifier],
+ params[:changes], push_options.as_json)
+
+ mr_options = push_options.get(:merge_request)
+ if mr_options.present?
+ message = process_mr_push_options(mr_options, project, user, params[:changes])
+ response.add_alert_message(message)
+ end
+
+ broadcast_message = BroadcastMessage.current&.last&.message
+ response.add_alert_message(broadcast_message)
+
+ response.add_merge_request_urls(merge_request_urls)
+
+ # A user is not guaranteed to be returned; an orphaned write deploy
+ # key could be used
+ if user
+ redirect_message = Gitlab::Checks::ProjectMoved.fetch_message(user.id, project.id)
+ project_created_message = Gitlab::Checks::ProjectCreated.fetch_message(user.id, project.id)
+
+ response.add_basic_message(redirect_message)
+ response.add_basic_message(project_created_message)
+ end
+
+ present response, with: Entities::InternalPostReceive::Response
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb
index 5d1b40e3bff..def36dc8529 100644
--- a/lib/api/release/links.rb
+++ b/lib/api/release/links.rb
@@ -5,7 +5,7 @@ module API
class Links < Grape::API
include PaginationParams
- RELEASE_ENDPOINT_REQUIREMETS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
+ RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
before { authorize! :read_release, user_project }
@@ -17,7 +17,7 @@ module API
params do
requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
end
- resource 'releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ resource 'releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
resource :assets do
desc 'Get a list of links of a release' do
detail 'This feature was introduced in GitLab 11.7.'
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index 7a3d804c30c..5a31581c4da 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -4,7 +4,7 @@ module API
class Releases < Grape::API
include PaginationParams
- RELEASE_ENDPOINT_REQUIREMETS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
+ RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
before { authorize_read_releases! }
@@ -33,7 +33,7 @@ module API
params do
requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
end
- get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
authorize_download_code!
present release, with: Entities::Release, current_user: current_user
@@ -54,6 +54,7 @@ module API
requires :url, type: String
end
end
+ optional :milestone, type: String, desc: 'The title of the related milestone'
optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
end
post ':id/releases' do
@@ -79,8 +80,9 @@ module API
optional :name, type: String, desc: 'The name of the release'
optional :description, type: String, desc: 'Release notes with markdown support'
optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready.'
+ optional :milestone, type: String, desc: 'The title of the related milestone'
end
- put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
authorize_update_release!
result = ::Releases::UpdateService
@@ -101,7 +103,7 @@ module API
params do
requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
end
- delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
authorize_destroy_release!
result = ::Releases::DestroyService
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 6769bd95c2b..bdc46abeb9f 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -265,7 +265,8 @@ module Gitlab
:read_project,
:build_download_code,
:build_read_container_image,
- :build_create_container_image
+ :build_create_container_image,
+ :build_destroy_container_image
]
end
diff --git a/lib/gitlab/auth/unique_ips_limiter.rb b/lib/gitlab/auth/unique_ips_limiter.rb
index 31dd61ae6cf..97e78ecf094 100644
--- a/lib/gitlab/auth/unique_ips_limiter.rb
+++ b/lib/gitlab/auth/unique_ips_limiter.rb
@@ -3,7 +3,7 @@
module Gitlab
module Auth
class UniqueIpsLimiter
- USER_UNIQUE_IPS_PREFIX = 'user_unique_ips'.freeze
+ USER_UNIQUE_IPS_PREFIX = 'user_unique_ips'
class << self
def limit_user_id!(user_id)
diff --git a/lib/gitlab/auth/user_auth_finders.rb b/lib/gitlab/auth/user_auth_finders.rb
index bba7e2cbb3c..97755117edc 100644
--- a/lib/gitlab/auth/user_auth_finders.rb
+++ b/lib/gitlab/auth/user_auth_finders.rb
@@ -20,7 +20,7 @@ module Gitlab
module UserAuthFinders
include Gitlab::Utils::StrongMemoize
- PRIVATE_TOKEN_HEADER = 'HTTP_PRIVATE_TOKEN'.freeze
+ PRIVATE_TOKEN_HEADER = 'HTTP_PRIVATE_TOKEN'
PRIVATE_TOKEN_PARAM = :private_token
# Check the Rails session for valid authentication details
diff --git a/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check.rb b/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check.rb
index e948cedaad5..de0c357ab1c 100644
--- a/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check.rb
+++ b/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check.rb
@@ -7,7 +7,7 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
RESCHEDULE_DELAY = 3.hours
- WORKER = 'PopulateMergeRequestAssigneesTable'.freeze
+ WORKER = 'PopulateMergeRequestAssigneesTable'
DeadJobsError = Class.new(StandardError)
def perform
diff --git a/lib/gitlab/background_migration/prepare_untracked_uploads.rb b/lib/gitlab/background_migration/prepare_untracked_uploads.rb
index 2ac51dd7b55..3d943205783 100644
--- a/lib/gitlab/background_migration/prepare_untracked_uploads.rb
+++ b/lib/gitlab/background_migration/prepare_untracked_uploads.rb
@@ -10,15 +10,15 @@ module Gitlab
include ::Gitlab::Utils::StrongMemoize
FIND_BATCH_SIZE = 500
- RELATIVE_UPLOAD_DIR = "uploads".freeze
+ RELATIVE_UPLOAD_DIR = "uploads"
ABSOLUTE_UPLOAD_DIR = File.join(
Gitlab.config.uploads.storage_path,
RELATIVE_UPLOAD_DIR
)
- FOLLOW_UP_MIGRATION = 'PopulateUntrackedUploads'.freeze
+ FOLLOW_UP_MIGRATION = 'PopulateUntrackedUploads'
START_WITH_ROOT_REGEX = %r{\A#{Gitlab.config.uploads.storage_path}/}.freeze
- EXCLUDED_HASHED_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/@hashed/*".freeze
- EXCLUDED_TMP_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/tmp/*".freeze
+ EXCLUDED_HASHED_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/@hashed/*"
+ EXCLUDED_TMP_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/tmp/*"
# This class is used to iterate over batches of
# `untracked_files_for_uploads` rows.
diff --git a/lib/gitlab/bitbucket_server_import/importer.rb b/lib/gitlab/bitbucket_server_import/importer.rb
index ff2694abd5e..93c6fdcf69c 100644
--- a/lib/gitlab/bitbucket_server_import/importer.rb
+++ b/lib/gitlab/bitbucket_server_import/importer.rb
@@ -7,7 +7,7 @@ module Gitlab
attr_reader :project, :project_key, :repository_slug, :client, :errors, :users
attr_accessor :logger
- REMOTE_NAME = 'bitbucket_server'.freeze
+ REMOTE_NAME = 'bitbucket_server'
BATCH_SIZE = 100
TempBranch = Struct.new(:name, :sha)
diff --git a/lib/gitlab/checks/lfs_check.rb b/lib/gitlab/checks/lfs_check.rb
index 67a65d61441..7b013567a03 100644
--- a/lib/gitlab/checks/lfs_check.rb
+++ b/lib/gitlab/checks/lfs_check.rb
@@ -3,8 +3,8 @@
module Gitlab
module Checks
class LfsCheck < BaseChecker
- LOG_MESSAGE = "Scanning repository for blobs stored in LFS and verifying their files have been uploaded to GitLab...".freeze
- ERROR_MESSAGE = 'LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".'.freeze
+ LOG_MESSAGE = 'Scanning repository for blobs stored in LFS and verifying their files have been uploaded to GitLab...'
+ ERROR_MESSAGE = 'LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".'
def validate!
return unless Feature.enabled?(:lfs_check, default_enabled: true)
diff --git a/lib/gitlab/checks/project_created.rb b/lib/gitlab/checks/project_created.rb
index 0058a402a62..362562068e9 100644
--- a/lib/gitlab/checks/project_created.rb
+++ b/lib/gitlab/checks/project_created.rb
@@ -3,7 +3,7 @@
module Gitlab
module Checks
class ProjectCreated < PostPushMessage
- PROJECT_CREATED = "project_created".freeze
+ PROJECT_CREATED = "project_created"
def message
<<~MESSAGE
diff --git a/lib/gitlab/checks/project_moved.rb b/lib/gitlab/checks/project_moved.rb
index cb3b7acaaad..6f04fddc6c4 100644
--- a/lib/gitlab/checks/project_moved.rb
+++ b/lib/gitlab/checks/project_moved.rb
@@ -3,7 +3,7 @@
module Gitlab
module Checks
class ProjectMoved < PostPushMessage
- REDIRECT_NAMESPACE = "redirect_namespace".freeze
+ REDIRECT_NAMESPACE = "redirect_namespace"
def initialize(project, user, protocol, redirected_path)
@redirected_path = redirected_path
diff --git a/lib/gitlab/ci/build/port.rb b/lib/gitlab/ci/build/port.rb
index 6c4656ffea2..017b31b4f77 100644
--- a/lib/gitlab/ci/build/port.rb
+++ b/lib/gitlab/ci/build/port.rb
@@ -4,8 +4,8 @@ module Gitlab
module Ci
module Build
class Port
- DEFAULT_PORT_NAME = 'default_port'.freeze
- DEFAULT_PORT_PROTOCOL = 'http'.freeze
+ DEFAULT_PORT_NAME = 'default_port'
+ DEFAULT_PORT_PROTOCOL = 'http'
attr_reader :number, :protocol, :name
diff --git a/lib/gitlab/ci/build/step.rb b/lib/gitlab/ci/build/step.rb
index 7fcabc035ac..48111ae5717 100644
--- a/lib/gitlab/ci/build/step.rb
+++ b/lib/gitlab/ci/build/step.rb
@@ -4,9 +4,9 @@ module Gitlab
module Ci
module Build
class Step
- WHEN_ON_FAILURE = 'on_failure'.freeze
- WHEN_ON_SUCCESS = 'on_success'.freeze
- WHEN_ALWAYS = 'always'.freeze
+ WHEN_ON_FAILURE = 'on_failure'
+ WHEN_ON_SUCCESS = 'on_success'
+ WHEN_ALWAYS = 'always'
attr_reader :name
attr_accessor :script, :timeout, :when, :allow_failure
diff --git a/lib/gitlab/ci/config/entry/cache.rb b/lib/gitlab/ci/config/entry/cache.rb
index 7b94af24c09..ef07c319ce4 100644
--- a/lib/gitlab/ci/config/entry/cache.rb
+++ b/lib/gitlab/ci/config/entry/cache.rb
@@ -12,7 +12,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[key untracked paths policy].freeze
- DEFAULT_POLICY = 'pull-push'.freeze
+ DEFAULT_POLICY = 'pull-push'
validations do
validates :config, allowed_keys: ALLOWED_KEYS
diff --git a/lib/gitlab/ci/config/external/file/template.rb b/lib/gitlab/ci/config/external/file/template.rb
index 54f4cf74c4d..db56f6a9b00 100644
--- a/lib/gitlab/ci/config/external/file/template.rb
+++ b/lib/gitlab/ci/config/external/file/template.rb
@@ -8,7 +8,7 @@ module Gitlab
class Template < Base
attr_reader :location, :project
- SUFFIX = '.gitlab-ci.yml'.freeze
+ SUFFIX = '.gitlab-ci.yml'
def initialize(params, context)
@location = params[:template]
diff --git a/lib/gitlab/ci/cron_parser.rb b/lib/gitlab/ci/cron_parser.rb
index 94f4a4e36c9..1d7e7ea0f9a 100644
--- a/lib/gitlab/ci/cron_parser.rb
+++ b/lib/gitlab/ci/cron_parser.rb
@@ -3,8 +3,8 @@
module Gitlab
module Ci
class CronParser
- VALID_SYNTAX_SAMPLE_TIME_ZONE = 'UTC'.freeze
- VALID_SYNTAX_SAMPLE_CRON = '* * * * *'.freeze
+ VALID_SYNTAX_SAMPLE_TIME_ZONE = 'UTC'
+ VALID_SYNTAX_SAMPLE_CRON = '* * * * *'
def initialize(cron, cron_timezone = 'UTC')
@cron = cron
diff --git a/lib/gitlab/ci/pipeline/chain/helpers.rb b/lib/gitlab/ci/pipeline/chain/helpers.rb
index 6bb3a75291b..8ccb1066575 100644
--- a/lib/gitlab/ci/pipeline/chain/helpers.rb
+++ b/lib/gitlab/ci/pipeline/chain/helpers.rb
@@ -5,7 +5,12 @@ module Gitlab
module Pipeline
module Chain
module Helpers
- def error(message)
+ def error(message, config_error: false)
+ if config_error && command.save_incompleted
+ pipeline.yaml_errors = message
+ pipeline.drop!(:config_error)
+ end
+
pipeline.errors.add(:base, message)
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/populate.rb b/lib/gitlab/ci/pipeline/chain/populate.rb
index 65029f5ce7f..13eca5a9d28 100644
--- a/lib/gitlab/ci/pipeline/chain/populate.rb
+++ b/lib/gitlab/ci/pipeline/chain/populate.rb
@@ -26,7 +26,7 @@ module Gitlab
# Gather all runtime build/stage errors
#
if seeds_errors = pipeline.stage_seeds.flat_map(&:errors).compact.presence
- return error(seeds_errors.join("\n"))
+ return error(seeds_errors.join("\n"), config_error: true)
end
##
diff --git a/lib/gitlab/ci/reports/test_case.rb b/lib/gitlab/ci/reports/test_case.rb
index 292e273a03a..fdeaad698b9 100644
--- a/lib/gitlab/ci/reports/test_case.rb
+++ b/lib/gitlab/ci/reports/test_case.rb
@@ -4,10 +4,10 @@ module Gitlab
module Ci
module Reports
class TestCase
- STATUS_SUCCESS = 'success'.freeze
- STATUS_FAILED = 'failed'.freeze
- STATUS_SKIPPED = 'skipped'.freeze
- STATUS_ERROR = 'error'.freeze
+ STATUS_SUCCESS = 'success'
+ STATUS_FAILED = 'failed'
+ STATUS_SKIPPED = 'skipped'
+ STATUS_ERROR = 'error'
STATUS_TYPES = [STATUS_SUCCESS, STATUS_FAILED, STATUS_SKIPPED, STATUS_ERROR].freeze
attr_reader :name, :classname, :execution_time, :status, :file, :system_output, :stack_trace, :key
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 5c1c0c142e5..f704266b73d 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -54,7 +54,7 @@ variables:
ROLLOUT_RESOURCE_TYPE: deployment
- DOCKER_TLS_CERTDIR: "" # https://gitlab.com/gitlab-org/gitlab-runner/issues/4501
+ DOCKER_TLS_CERTDIR: "" # https://gitlab.com/gitlab-org/gitlab-runner/issues/4501
stages:
- build
@@ -73,16 +73,16 @@ stages:
- cleanup
include:
- - template: Jobs/Build.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
- - template: Jobs/Test.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
- - template: Jobs/Code-Quality.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
- - template: Jobs/Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
- - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
- - template: Security/DAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml
- - template: Security/Container-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
- - template: Security/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
- - template: Security/License-Management.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/License-Management.gitlab-ci.yml
- - template: Security/SAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+ - template: Jobs/Build.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
+ - template: Jobs/Test.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
+ - template: Jobs/Code-Quality.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+ - template: Jobs/Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+ - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
+ - template: Security/DAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
+ - template: Security/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+ - template: Security/License-Management.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/License-Management.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
# Override DAST job to exclude master branch
dast:
diff --git a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
index 3adc6a72874..3cdb7b5420c 100644
--- a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
@@ -25,8 +25,9 @@ code_quality:
expire_in: 1 week
dependencies: []
only:
- - branches
- - tags
+ refs:
+ - branches
+ - tags
except:
variables:
- $CODE_QUALITY_DISABLED
diff --git a/lib/gitlab/cleanup/project_upload_file_finder.rb b/lib/gitlab/cleanup/project_upload_file_finder.rb
index 5aace564c2d..3d35d474f5d 100644
--- a/lib/gitlab/cleanup/project_upload_file_finder.rb
+++ b/lib/gitlab/cleanup/project_upload_file_finder.rb
@@ -5,9 +5,9 @@ module Gitlab
class ProjectUploadFileFinder
FIND_BATCH_SIZE = 500
ABSOLUTE_UPLOAD_DIR = FileUploader.root.freeze
- EXCLUDED_SYSTEM_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/-/*".freeze
- EXCLUDED_HASHED_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/@hashed/*".freeze
- EXCLUDED_TMP_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/tmp/*".freeze
+ EXCLUDED_SYSTEM_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/-/*"
+ EXCLUDED_HASHED_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/@hashed/*"
+ EXCLUDED_TMP_UPLOADS_PATH = "#{ABSOLUTE_UPLOAD_DIR}/tmp/*"
# Paths are relative to the upload directory
def each_file_batch(batch_size: FIND_BATCH_SIZE, &block)
diff --git a/lib/gitlab/correlation_id.rb b/lib/gitlab/correlation_id.rb
deleted file mode 100644
index 0f9bde4390e..00000000000
--- a/lib/gitlab/correlation_id.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module CorrelationId
- LOG_KEY = 'correlation_id'.freeze
-
- class << self
- def use_id(correlation_id, &blk)
- # always generate a id if null is passed
- correlation_id ||= new_id
-
- ids.push(correlation_id || new_id)
-
- begin
- yield(current_id)
- ensure
- ids.pop
- end
- end
-
- def current_id
- ids.last
- end
-
- def current_or_new_id
- current_id || new_id
- end
-
- private
-
- def ids
- Thread.current[:correlation_id] ||= []
- end
-
- def new_id
- SecureRandom.uuid
- end
- end
- end
-end
diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb
index 5424298723e..d30d5a38670 100644
--- a/lib/gitlab/danger/helper.rb
+++ b/lib/gitlab/danger/helper.rb
@@ -110,7 +110,8 @@ module Gitlab
karma\.config\.js |
webpack\.config\.js |
package\.json |
- yarn\.lock
+ yarn\.lock |
+ \.gitlab/ci/frontend\.gitlab-ci\.yml
)\z}x => :frontend,
%r{\A(ee/)?db/(?!fixtures)[^/]+} => :database,
diff --git a/lib/gitlab/database/sha_attribute.rb b/lib/gitlab/database/sha_attribute.rb
index ddbabc9098e..776e80701f1 100644
--- a/lib/gitlab/database/sha_attribute.rb
+++ b/lib/gitlab/database/sha_attribute.rb
@@ -12,7 +12,7 @@ module Gitlab
# using them as if they were stored as string values. This gives you the
# ease of use of string values, but without the storage overhead.
class ShaAttribute < BINARY_TYPE
- PACK_FORMAT = 'H*'.freeze
+ PACK_FORMAT = 'H*'
# Casts binary data to a SHA1 in hexadecimal.
def deserialize(value)
diff --git a/lib/gitlab/downtime_check/message.rb b/lib/gitlab/downtime_check/message.rb
index ec38bd769a3..5debb754943 100644
--- a/lib/gitlab/downtime_check/message.rb
+++ b/lib/gitlab/downtime_check/message.rb
@@ -5,8 +5,8 @@ module Gitlab
class Message
attr_reader :path, :offline
- OFFLINE = "\e[31moffline\e[0m".freeze
- ONLINE = "\e[32monline\e[0m".freeze
+ OFFLINE = "\e[31moffline\e[0m"
+ ONLINE = "\e[32monline\e[0m"
# path - The file path of the migration.
# offline - When set to `true` the migration will require downtime.
diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb
index 86e532766b1..20c31e06905 100644
--- a/lib/gitlab/ee_compat_check.rb
+++ b/lib/gitlab/ee_compat_check.rb
@@ -1,11 +1,12 @@
+# coding: utf-8
# frozen_string_literal: true
# rubocop: disable Rails/Output
module Gitlab
# Checks if a set of migrations requires downtime or not.
class EeCompatCheck
- CANONICAL_CE_PROJECT_URL = 'https://gitlab.com/gitlab-org/gitlab-ce'.freeze
- CANONICAL_EE_REPO_URL = 'https://gitlab.com/gitlab-org/gitlab-ee.git'.freeze
+ CANONICAL_CE_PROJECT_URL = 'https://gitlab.com/gitlab-org/gitlab-ce'
+ CANONICAL_EE_REPO_URL = 'https://gitlab.com/gitlab-org/gitlab-ee.git'
CHECK_DIR = Rails.root.join('ee_compat_check')
IGNORED_FILES_REGEX = /VERSION|CHANGELOG\.md|doc\/.+/i.freeze
PLEASE_READ_THIS_BANNER = %Q{
diff --git a/lib/gitlab/etag_caching/store.rb b/lib/gitlab/etag_caching/store.rb
index 2395e7be026..1d2f0d7bbf4 100644
--- a/lib/gitlab/etag_caching/store.rb
+++ b/lib/gitlab/etag_caching/store.rb
@@ -4,7 +4,7 @@ module Gitlab
module EtagCaching
class Store
EXPIRY_TIME = 20.minutes
- SHARED_STATE_NAMESPACE = 'etag:'.freeze
+ SHARED_STATE_NAMESPACE = 'etag:'
def get(key)
Gitlab::Redis::SharedState.with { |redis| redis.get(redis_shared_state_key(key)) }
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index df9f33baec2..8d13c74dca2 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -7,11 +7,11 @@ module Gitlab
# The ID of empty tree.
# See http://stackoverflow.com/a/40884093/1856239 and
# https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012
- EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze
+ EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
BLANK_SHA = ('0' * 40).freeze
COMMIT_ID = /\A[0-9a-f]{40}\z/.freeze
- TAG_REF_PREFIX = "refs/tags/".freeze
- BRANCH_REF_PREFIX = "refs/heads/".freeze
+ TAG_REF_PREFIX = "refs/tags/"
+ BRANCH_REF_PREFIX = "refs/heads/"
BaseError = Class.new(StandardError)
CommandError = Class.new(BaseError)
diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb
index 5c70cb6c66c..cb9154cb1e8 100644
--- a/lib/gitlab/git/diff_collection.rb
+++ b/lib/gitlab/git/diff_collection.rb
@@ -81,6 +81,12 @@ module Gitlab
end
end
+ def line_count
+ populate!
+
+ @line_count
+ end
+
def decorate!
collection = each_with_index do |element, i|
@array[i] = yield(element)
diff --git a/lib/gitlab/git/lfs_pointer_file.rb b/lib/gitlab/git/lfs_pointer_file.rb
index b7019a221ac..efd84e30ad9 100644
--- a/lib/gitlab/git/lfs_pointer_file.rb
+++ b/lib/gitlab/git/lfs_pointer_file.rb
@@ -3,8 +3,8 @@
module Gitlab
module Git
class LfsPointerFile
- VERSION = "https://git-lfs.github.com/spec/v1".freeze
- VERSION_LINE = "version #{VERSION}".freeze
+ VERSION = "https://git-lfs.github.com/spec/v1"
+ VERSION_LINE = "version #{VERSION}"
def initialize(data)
@data = data
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 27032602828..4ea618f063b 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -15,9 +15,9 @@ module Gitlab
SEARCH_CONTEXT_LINES = 3
REV_LIST_COMMIT_LIMIT = 2_000
- GITALY_INTERNAL_URL = 'ssh://gitaly/internal.git'.freeze
+ GITALY_INTERNAL_URL = 'ssh://gitaly/internal.git'
GITLAB_PROJECTS_TIMEOUT = Gitlab.config.gitlab_shell.git_timeout
- EMPTY_REPOSITORY_CHECKSUM = '0000000000000000000000000000000000000000'.freeze
+ EMPTY_REPOSITORY_CHECKSUM = '0000000000000000000000000000000000000000'
NoRepository = Class.new(StandardError)
InvalidRepository = Class.new(StandardError)
diff --git a/lib/gitlab/git/util.rb b/lib/gitlab/git/util.rb
index 03c2c1367b0..cf8571bf917 100644
--- a/lib/gitlab/git/util.rb
+++ b/lib/gitlab/git/util.rb
@@ -5,7 +5,7 @@
module Gitlab
module Git
module Util
- LINE_SEP = "\n".freeze
+ LINE_SEP = "\n"
def self.count_lines(string)
case string[-1]
diff --git a/lib/gitlab/github_import/issuable_finder.rb b/lib/gitlab/github_import/issuable_finder.rb
index 211915f1d87..c81603a1aa9 100644
--- a/lib/gitlab/github_import/issuable_finder.rb
+++ b/lib/gitlab/github_import/issuable_finder.rb
@@ -10,7 +10,7 @@ module Gitlab
attr_reader :project, :object
# The base cache key to use for storing/retrieving issuable IDs.
- CACHE_KEY = 'github-import/issuable-finder/%{project}/%{type}/%{iid}'.freeze
+ CACHE_KEY = 'github-import/issuable-finder/%{project}/%{type}/%{iid}'
# project - An instance of `Project`.
# object - The object to look up or set a database ID for.
diff --git a/lib/gitlab/github_import/label_finder.rb b/lib/gitlab/github_import/label_finder.rb
index d2479a8f565..cad39e48e43 100644
--- a/lib/gitlab/github_import/label_finder.rb
+++ b/lib/gitlab/github_import/label_finder.rb
@@ -6,7 +6,7 @@ module Gitlab
attr_reader :project
# The base cache key to use for storing/retrieving label IDs.
- CACHE_KEY = 'github-import/label-finder/%{project}/%{name}'.freeze
+ CACHE_KEY = 'github-import/label-finder/%{project}/%{name}'
# project - An instance of `Project`.
def initialize(project)
diff --git a/lib/gitlab/github_import/milestone_finder.rb b/lib/gitlab/github_import/milestone_finder.rb
index 5625730e796..a157a1e1ff5 100644
--- a/lib/gitlab/github_import/milestone_finder.rb
+++ b/lib/gitlab/github_import/milestone_finder.rb
@@ -6,7 +6,7 @@ module Gitlab
attr_reader :project
# The base cache key to use for storing/retrieving milestone IDs.
- CACHE_KEY = 'github-import/milestone-finder/%{project}/%{iid}'.freeze
+ CACHE_KEY = 'github-import/milestone-finder/%{project}/%{iid}'
# project - An instance of `Project`
def initialize(project)
diff --git a/lib/gitlab/github_import/page_counter.rb b/lib/gitlab/github_import/page_counter.rb
index c3db2d0b469..a3e7b3c1afc 100644
--- a/lib/gitlab/github_import/page_counter.rb
+++ b/lib/gitlab/github_import/page_counter.rb
@@ -9,7 +9,7 @@ module Gitlab
attr_reader :cache_key
# The base cache key to use for storing the last page number.
- CACHE_KEY = 'github-importer/page-counter/%{project}/%{collection}'.freeze
+ CACHE_KEY = 'github-importer/page-counter/%{project}/%{collection}'
def initialize(project, collection)
@cache_key = CACHE_KEY % { project: project.id, collection: collection }
diff --git a/lib/gitlab/github_import/parallel_scheduling.rb b/lib/gitlab/github_import/parallel_scheduling.rb
index d4d1357f5a3..849a66d47ed 100644
--- a/lib/gitlab/github_import/parallel_scheduling.rb
+++ b/lib/gitlab/github_import/parallel_scheduling.rb
@@ -7,7 +7,7 @@ module Gitlab
# The base cache key to use for tracking already imported objects.
ALREADY_IMPORTED_CACHE_KEY =
- 'github-importer/already-imported/%{project}/%{collection}'.freeze
+ 'github-importer/already-imported/%{project}/%{collection}'
# project - An instance of `Project`.
# client - An instance of `Gitlab::GithubImport::Client`.
diff --git a/lib/gitlab/github_import/user_finder.rb b/lib/gitlab/github_import/user_finder.rb
index 30283f147ef..51a532437bd 100644
--- a/lib/gitlab/github_import/user_finder.rb
+++ b/lib/gitlab/github_import/user_finder.rb
@@ -16,17 +16,17 @@ module Gitlab
# The base cache key to use for caching user IDs for a given GitHub user
# ID.
- ID_CACHE_KEY = 'github-import/user-finder/user-id/%s'.freeze
+ ID_CACHE_KEY = 'github-import/user-finder/user-id/%s'
# The base cache key to use for caching user IDs for a given GitHub email
# address.
ID_FOR_EMAIL_CACHE_KEY =
- 'github-import/user-finder/id-for-email/%s'.freeze
+ 'github-import/user-finder/id-for-email/%s'
# The base cache key to use for caching the Email addresses of GitHub
# usernames.
EMAIL_FOR_USERNAME_CACHE_KEY =
- 'github-import/user-finder/email-for-username/%s'.freeze
+ 'github-import/user-finder/email-for-username/%s'
# project - An instance of `Project`
# client - An instance of `Gitlab::GithubImport::Client`
diff --git a/lib/gitlab/graphql/authorize/authorize_field_service.rb b/lib/gitlab/graphql/authorize/authorize_field_service.rb
index 3b5dde2fde5..c7f430490d6 100644
--- a/lib/gitlab/graphql/authorize/authorize_field_service.rb
+++ b/lib/gitlab/graphql/authorize/authorize_field_service.rb
@@ -54,14 +54,14 @@ module Gitlab
# The field is a built-in/scalar type, or a list of scalars
# authorize using the parent's object
parent_typed_object.object
- elsif resolved_type.respond_to?(:object)
- # The field is a type representing a single object, we'll authorize
- # against the object directly
- resolved_type.object
elsif @field.connection? || resolved_type.is_a?(Array)
# The field is a connection or a list of non-built-in types, we'll
# authorize each element when rendering
nil
+ elsif resolved_type.respond_to?(:object)
+ # The field is a type representing a single object, we'll authorize
+ # against the object directly
+ resolved_type.object
else
# Resolved type is a single object that might not be loaded yet by
# the batchloader, we'll authorize that
@@ -74,9 +74,9 @@ module Gitlab
# Authorizing fields representing scalars, or a simple field with an object
resolved_type if allowed_access?(current_user, authorizing_object)
elsif @field.connection?
- # A connection with pagination, modify the visible nodes in on the
+ # A connection with pagination, modify the visible nodes on the
# connection type in place
- resolved_type.edge_nodes.to_a.keep_if { |node| allowed_access?(current_user, node) }
+ resolved_type.object.edge_nodes.to_a.keep_if { |node| allowed_access?(current_user, node) }
resolved_type
elsif resolved_type.is_a? Array
# A simple list of rendered types each object being an object to authorize
diff --git a/lib/gitlab/graphql/authorize/authorize_resource.rb b/lib/gitlab/graphql/authorize/authorize_resource.rb
index ef5caaf5b0e..6844367454f 100644
--- a/lib/gitlab/graphql/authorize/authorize_resource.rb
+++ b/lib/gitlab/graphql/authorize/authorize_resource.rb
@@ -29,19 +29,25 @@ module Gitlab
def authorized_find!(*args)
object = find_object(*args)
+ object = object.sync if object.respond_to?(:sync)
+
authorize!(object)
object
end
def authorize!(object)
- unless authorized?(object)
+ unless authorized_resource?(object)
raise Gitlab::Graphql::Errors::ResourceNotAvailable,
"The resource that you are attempting to access does not exist or you don't have permission to perform this action"
end
end
- def authorized?(object)
+ # this was named `#authorized?`, however it conflicts with the native
+ # graphql gem version
+ # TODO consider adopting the gem's built in authorization system
+ # https://gitlab.com/gitlab-org/gitlab-ee/issues/13984
+ def authorized_resource?(object)
# Sanity check. We don't want to accidentally allow a developer to authorize
# without first adding permissions to authorize against
if self.class.required_permissions.empty?
diff --git a/lib/gitlab/graphql/loaders/batch_lfs_oid_loader.rb b/lib/gitlab/graphql/loaders/batch_lfs_oid_loader.rb
index 8f34e58a771..67511c124e4 100644
--- a/lib/gitlab/graphql/loaders/batch_lfs_oid_loader.rb
+++ b/lib/gitlab/graphql/loaders/batch_lfs_oid_loader.rb
@@ -9,7 +9,7 @@ module Gitlab
end
def find
- BatchLoader.for(blob_id).batch(key: repository) do |blob_ids, loader, batch_args|
+ BatchLoader::GraphQL.for(blob_id).batch(key: repository) do |blob_ids, loader, batch_args|
Gitlab::Git::Blob.batch_lfs_pointers(batch_args[:key], blob_ids).each do |loaded_blob|
loader.call(loaded_blob.id, loaded_blob.lfs_oid)
end
diff --git a/lib/gitlab/graphql/loaders/batch_model_loader.rb b/lib/gitlab/graphql/loaders/batch_model_loader.rb
index 50d3293fcbb..164fe74148c 100644
--- a/lib/gitlab/graphql/loaders/batch_model_loader.rb
+++ b/lib/gitlab/graphql/loaders/batch_model_loader.rb
@@ -12,7 +12,7 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def find
- BatchLoader.for({ model: model_class, id: model_id.to_i }).batch do |loader_info, loader|
+ BatchLoader::GraphQL.for({ model: model_class, id: model_id.to_i }).batch do |loader_info, loader|
per_model = loader_info.group_by { |info| info[:model] }
per_model.each do |model, info|
ids = info.map { |i| i[:id] }
diff --git a/lib/gitlab/graphql/loaders/batch_project_statistics_loader.rb b/lib/gitlab/graphql/loaders/batch_project_statistics_loader.rb
index 5e151f4dbd7..449f4160a6c 100644
--- a/lib/gitlab/graphql/loaders/batch_project_statistics_loader.rb
+++ b/lib/gitlab/graphql/loaders/batch_project_statistics_loader.rb
@@ -11,7 +11,7 @@ module Gitlab
end
def find
- BatchLoader.for(project_id).batch do |project_ids, loader|
+ BatchLoader::GraphQL.for(project_id).batch do |project_ids, loader|
ProjectStatistics.for_project_ids(project_ids).each do |statistics|
loader.call(statistics.project_id, statistics)
end
diff --git a/lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader.rb b/lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader.rb
index a0312366d66..366aa74d435 100644
--- a/lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader.rb
+++ b/lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader.rb
@@ -11,7 +11,7 @@ module Gitlab
end
def find
- BatchLoader.for(namespace_id).batch do |namespace_ids, loader|
+ BatchLoader::GraphQL.for(namespace_id).batch do |namespace_ids, loader|
Namespace::RootStorageStatistics.for_namespace_ids(namespace_ids).each do |statistics|
loader.call(statistics.namespace_id, statistics)
end
diff --git a/lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb b/lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb
index 81c5cabf451..70344392138 100644
--- a/lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb
+++ b/lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb
@@ -11,7 +11,7 @@ module Gitlab
end
def find_last
- BatchLoader.for(sha).batch(key: project) do |shas, loader, args|
+ BatchLoader::GraphQL.for(sha).batch(key: project) do |shas, loader, args|
pipelines = args[:key].ci_pipelines.latest_for_shas(shas)
pipelines.each do |pipeline|
diff --git a/lib/gitlab/graphql/representation/submodule_tree_entry.rb b/lib/gitlab/graphql/representation/submodule_tree_entry.rb
index 65716dff75d..8d17cb9eecc 100644
--- a/lib/gitlab/graphql/representation/submodule_tree_entry.rb
+++ b/lib/gitlab/graphql/representation/submodule_tree_entry.rb
@@ -4,6 +4,8 @@ module Gitlab
module Graphql
module Representation
class SubmoduleTreeEntry < SimpleDelegator
+ include GlobalID::Identification
+
class << self
def decorate(submodules, tree)
repository = tree.repository
diff --git a/lib/gitlab/graphql/representation/tree_entry.rb b/lib/gitlab/graphql/representation/tree_entry.rb
index 7ea83db5876..7e347081a9b 100644
--- a/lib/gitlab/graphql/representation/tree_entry.rb
+++ b/lib/gitlab/graphql/representation/tree_entry.rb
@@ -4,6 +4,8 @@ module Gitlab
module Graphql
module Representation
class TreeEntry < SimpleDelegator
+ include GlobalID::Identification
+
class << self
def decorate(entries, repository)
return if entries.nil?
diff --git a/lib/gitlab/health_checks/gitaly_check.rb b/lib/gitlab/health_checks/gitaly_check.rb
index 898733fea5d..e560f87bf98 100644
--- a/lib/gitlab/health_checks/gitaly_check.rb
+++ b/lib/gitlab/health_checks/gitaly_check.rb
@@ -5,7 +5,7 @@ module Gitlab
class GitalyCheck
extend BaseAbstractCheck
- METRIC_PREFIX = 'gitaly_health_check'.freeze
+ METRIC_PREFIX = 'gitaly_health_check'
class << self
def readiness
diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb
index bb46bd657e8..d08848a65a8 100644
--- a/lib/gitlab/import_export.rb
+++ b/lib/gitlab/import_export.rb
@@ -7,7 +7,7 @@ module Gitlab
# For every version update the version history in these docs must be kept up to date:
# - development/import_export.md
# - user/project/settings/import_export.md
- VERSION = '0.2.4'.freeze
+ VERSION = '0.2.4'
FILENAME_LIMIT = 50
def export_path(relative_path:)
diff --git a/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb b/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb
index d39b6fe5955..c5fb39b7b52 100644
--- a/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb
+++ b/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb
@@ -10,7 +10,7 @@ module Gitlab
StrategyError = Class.new(StandardError)
- AFTER_EXPORT_LOCK_FILE_NAME = '.after_export_action'.freeze
+ AFTER_EXPORT_LOCK_FILE_NAME = '.after_export_action'
private
diff --git a/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb b/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb
index acb7f225b17..aaa70f0b36d 100644
--- a/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb
+++ b/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb
@@ -4,9 +4,9 @@ module Gitlab
module ImportExport
module AfterExportStrategies
class WebUploadStrategy < BaseAfterExportStrategy
- PUT_METHOD = 'PUT'.freeze
- POST_METHOD = 'POST'.freeze
- INVALID_HTTP_METHOD = 'invalid. Only PUT and POST methods allowed.'.freeze
+ PUT_METHOD = 'PUT'
+ POST_METHOD = 'POST'
+ INVALID_HTTP_METHOD = 'invalid. Only PUT and POST methods allowed.'
validates :url, addressable_url: true
diff --git a/lib/gitlab/incoming_email.rb b/lib/gitlab/incoming_email.rb
index 8b346f6d7d2..eece4edf895 100644
--- a/lib/gitlab/incoming_email.rb
+++ b/lib/gitlab/incoming_email.rb
@@ -2,9 +2,9 @@
module Gitlab
module IncomingEmail
- UNSUBSCRIBE_SUFFIX = '-unsubscribe'.freeze
- UNSUBSCRIBE_SUFFIX_LEGACY = '+unsubscribe'.freeze
- WILDCARD_PLACEHOLDER = '%{key}'.freeze
+ UNSUBSCRIBE_SUFFIX = '-unsubscribe'
+ UNSUBSCRIBE_SUFFIX_LEGACY = '+unsubscribe'
+ WILDCARD_PLACEHOLDER = '%{key}'
class << self
def enabled?
diff --git a/lib/gitlab/job_waiter.rb b/lib/gitlab/job_waiter.rb
index e97e961771c..90dbe4d005d 100644
--- a/lib/gitlab/job_waiter.rb
+++ b/lib/gitlab/job_waiter.rb
@@ -17,7 +17,7 @@ module Gitlab
# push to that array when done. Once the waiter has popped `count` items, it
# knows all the jobs are done.
class JobWaiter
- KEY_PREFIX = "gitlab:job_waiter".freeze
+ KEY_PREFIX = "gitlab:job_waiter"
def self.notify(key, jid)
Gitlab::Redis::SharedState.with { |redis| redis.lpush(key, jid) }
diff --git a/lib/gitlab/jwt_authenticatable.rb b/lib/gitlab/jwt_authenticatable.rb
new file mode 100644
index 00000000000..1270a148e8d
--- /dev/null
+++ b/lib/gitlab/jwt_authenticatable.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module JwtAuthenticatable
+ # Supposedly the effective key size for HMAC-SHA256 is 256 bits, i.e. 32
+ # bytes https://tools.ietf.org/html/rfc4868#section-2.6
+ SECRET_LENGTH = 32
+
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ include Gitlab::Utils::StrongMemoize
+
+ def decode_jwt_for_issuer(issuer, encoded_message)
+ JWT.decode(
+ encoded_message,
+ secret,
+ true,
+ { iss: issuer, verify_iss: true, algorithm: 'HS256' }
+ )
+ end
+
+ def secret
+ strong_memoize(:secret) do
+ Base64.strict_decode64(File.read(secret_path).chomp).tap do |bytes|
+ raise "#{secret_path} does not contain #{SECRET_LENGTH} bytes" if bytes.length != SECRET_LENGTH
+ end
+ end
+ end
+
+ def write_secret
+ bytes = SecureRandom.random_bytes(SECRET_LENGTH)
+ File.open(secret_path, 'w:BINARY', 0600) do |f|
+ f.chmod(0600) # If the file already existed, the '0600' passed to 'open' above was a no-op.
+ f.write(Base64.strict_encode64(bytes))
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm.rb b/lib/gitlab/kubernetes/helm.rb
index 6e4286589c1..16ed0cb0f8e 100644
--- a/lib/gitlab/kubernetes/helm.rb
+++ b/lib/gitlab/kubernetes/helm.rb
@@ -3,12 +3,12 @@
module Gitlab
module Kubernetes
module Helm
- HELM_VERSION = '2.14.3'.freeze
- KUBECTL_VERSION = '1.11.10'.freeze
- NAMESPACE = 'gitlab-managed-apps'.freeze
- SERVICE_ACCOUNT = 'tiller'.freeze
- CLUSTER_ROLE_BINDING = 'tiller-admin'.freeze
- CLUSTER_ROLE = 'cluster-admin'.freeze
+ HELM_VERSION = '2.14.3'
+ KUBECTL_VERSION = '1.11.10'
+ NAMESPACE = 'gitlab-managed-apps'
+ SERVICE_ACCOUNT = 'tiller'
+ CLUSTER_ROLE_BINDING = 'tiller-admin'
+ CLUSTER_ROLE = 'cluster-admin'
end
end
end
diff --git a/lib/gitlab/kubernetes/pod.rb b/lib/gitlab/kubernetes/pod.rb
index 81317e532b2..d247662dc3b 100644
--- a/lib/gitlab/kubernetes/pod.rb
+++ b/lib/gitlab/kubernetes/pod.rb
@@ -3,11 +3,11 @@
module Gitlab
module Kubernetes
module Pod
- PENDING = 'Pending'.freeze
- RUNNING = 'Running'.freeze
- SUCCEEDED = 'Succeeded'.freeze
- FAILED = 'Failed'.freeze
- UNKNOWN = 'Unknown'.freeze
+ PENDING = 'Pending'
+ RUNNING = 'Running'
+ SUCCEEDED = 'Succeeded'
+ FAILED = 'Failed'
+ UNKNOWN = 'Unknown'
PHASES = [PENDING, RUNNING, SUCCEEDED, FAILED, UNKNOWN].freeze
end
end
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index 128a5dd8936..2ec8c268d09 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -40,7 +40,7 @@ module Gitlab
end
def self.cache_key
- 'logger:'.freeze + self.full_log_path.to_s
+ 'logger:' + self.full_log_path.to_s
end
end
end
diff --git a/lib/gitlab/metrics/samplers/ruby_sampler.rb b/lib/gitlab/metrics/samplers/ruby_sampler.rb
index 3bfa3da35e0..c38769f39a9 100644
--- a/lib/gitlab/metrics/samplers/ruby_sampler.rb
+++ b/lib/gitlab/metrics/samplers/ruby_sampler.rb
@@ -6,7 +6,7 @@ module Gitlab
module Metrics
module Samplers
class RubySampler < BaseSampler
- GC_REPORT_BUCKETS = [0.001, 0.002, 0.005, 0.01, 0.05, 0.1, 0.5].freeze
+ GC_REPORT_BUCKETS = [0.005, 0.01, 0.02, 0.04, 0.07, 0.1, 0.5].freeze
def initialize(interval)
GC::Profiler.clear
diff --git a/lib/gitlab/metrics/subscribers/action_view.rb b/lib/gitlab/metrics/subscribers/action_view.rb
index c068f8017fd..2ed5878286a 100644
--- a/lib/gitlab/metrics/subscribers/action_view.rb
+++ b/lib/gitlab/metrics/subscribers/action_view.rb
@@ -15,7 +15,7 @@ module Gitlab
attach_to :action_view
- SERIES = 'views'.freeze
+ SERIES = 'views'
def render_template(event)
track(event) if current_transaction
diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb
index d7986685c65..9584285be7e 100644
--- a/lib/gitlab/metrics/transaction.rb
+++ b/lib/gitlab/metrics/transaction.rb
@@ -14,7 +14,7 @@ module Gitlab
THREAD_KEY = :_gitlab_metrics_transaction
# The series to store events (e.g. Git pushes) in.
- EVENT_SERIES = 'events'.freeze
+ EVENT_SERIES = 'events'
attr_reader :tags, :values, :method, :metrics
diff --git a/lib/gitlab/metrics/web_transaction.rb b/lib/gitlab/metrics/web_transaction.rb
index b2a43d46fb2..fa17548723e 100644
--- a/lib/gitlab/metrics/web_transaction.rb
+++ b/lib/gitlab/metrics/web_transaction.rb
@@ -3,8 +3,8 @@
module Gitlab
module Metrics
class WebTransaction < Transaction
- CONTROLLER_KEY = 'action_controller.instance'.freeze
- ENDPOINT_KEY = 'api.endpoint'.freeze
+ CONTROLLER_KEY = 'action_controller.instance'
+ ENDPOINT_KEY = 'api.endpoint'
ALLOWED_SUFFIXES = Set.new(%w[json js atom rss xml zip])
def initialize(env)
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index 433151b80e7..86b28e4e20a 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -28,7 +28,7 @@
module Gitlab
module Middleware
class Multipart
- RACK_ENV_KEY = 'HTTP_GITLAB_WORKHORSE_MULTIPART_FIELDS'.freeze
+ RACK_ENV_KEY = 'HTTP_GITLAB_WORKHORSE_MULTIPART_FIELDS'
class Handler
def initialize(env, message)
diff --git a/lib/gitlab/middleware/read_only/controller.rb b/lib/gitlab/middleware/read_only/controller.rb
index 53e55269c6e..802ff18fc58 100644
--- a/lib/gitlab/middleware/read_only/controller.rb
+++ b/lib/gitlab/middleware/read_only/controller.rb
@@ -5,9 +5,9 @@ module Gitlab
class ReadOnly
class Controller
DISALLOWED_METHODS = %w(POST PATCH PUT DELETE).freeze
- APPLICATION_JSON = 'application/json'.freeze
+ APPLICATION_JSON = 'application/json'
APPLICATION_JSON_TYPES = %W{#{APPLICATION_JSON} application/vnd.git-lfs+json}.freeze
- ERROR_MESSAGE = 'You cannot perform write operations on a read-only instance'.freeze
+ ERROR_MESSAGE = 'You cannot perform write operations on a read-only instance'
WHITELISTED_GIT_ROUTES = {
'projects/git_http' => %w{git_upload_pack git_receive_pack}
diff --git a/lib/gitlab/optimistic_locking.rb b/lib/gitlab/optimistic_locking.rb
index 0c0f46d3b77..d51d718c826 100644
--- a/lib/gitlab/optimistic_locking.rb
+++ b/lib/gitlab/optimistic_locking.rb
@@ -4,7 +4,8 @@ module Gitlab
module OptimisticLocking
module_function
- def retry_lock(subject, retries = 100, &block)
+ def retry_lock(subject, retries = nil, &block)
+ retries ||= 100
# TODO(Observability): We should be recording details of the number of retries and the duration of the total execution here
ActiveRecord::Base.transaction do
yield(subject)
diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb
index d9c28ff1181..ee2ef91c65c 100644
--- a/lib/gitlab/path_regex.rb
+++ b/lib/gitlab/path_regex.rb
@@ -125,9 +125,9 @@ module Gitlab
# allow non-regex validations, etc), `NAMESPACE_FORMAT_REGEX_JS` serves as a Javascript-compatible version of
# `NAMESPACE_FORMAT_REGEX`, with the negative lookbehind assertion removed. This means that the client-side validation
# will pass for usernames ending in `.atom` and `.git`, but will be caught by the server-side validation.
- PATH_START_CHAR = '[a-zA-Z0-9_\.]'.freeze
- PATH_REGEX_STR = PATH_START_CHAR + '[a-zA-Z0-9_\-\.]*'.freeze
- NAMESPACE_FORMAT_REGEX_JS = PATH_REGEX_STR + '[a-zA-Z0-9_\-]|[a-zA-Z0-9_]'.freeze
+ PATH_START_CHAR = '[a-zA-Z0-9_\.]'
+ PATH_REGEX_STR = PATH_START_CHAR + '[a-zA-Z0-9_\-\.]*'
+ NAMESPACE_FORMAT_REGEX_JS = PATH_REGEX_STR + '[a-zA-Z0-9_\-]|[a-zA-Z0-9_]'
NO_SUFFIX_REGEX = /(?<!\.git|\.atom)/.freeze
NAMESPACE_FORMAT_REGEX = /(?:#{NAMESPACE_FORMAT_REGEX_JS})#{NO_SUFFIX_REGEX}/.freeze
diff --git a/lib/gitlab/performance_bar.rb b/lib/gitlab/performance_bar.rb
index 68af290d069..4445c876e7a 100644
--- a/lib/gitlab/performance_bar.rb
+++ b/lib/gitlab/performance_bar.rb
@@ -2,7 +2,7 @@
module Gitlab
module PerformanceBar
- ALLOWED_USER_IDS_KEY = 'performance_bar_allowed_user_ids:v2'.freeze
+ ALLOWED_USER_IDS_KEY = 'performance_bar_allowed_user_ids:v2'
EXPIRY_TIME_L1_CACHE = 1.minute
EXPIRY_TIME_L2_CACHE = 5.minutes
diff --git a/lib/gitlab/polling_interval.rb b/lib/gitlab/polling_interval.rb
index 0f69990df63..fd66787b029 100644
--- a/lib/gitlab/polling_interval.rb
+++ b/lib/gitlab/polling_interval.rb
@@ -2,7 +2,7 @@
module Gitlab
class PollingInterval
- HEADER_NAME = 'Poll-Interval'.freeze
+ HEADER_NAME = 'Poll-Interval'
def self.set_header(response, interval:)
if polling_enabled?
diff --git a/lib/gitlab/private_commit_email.rb b/lib/gitlab/private_commit_email.rb
index 536fc9dae3a..886c2c32d36 100644
--- a/lib/gitlab/private_commit_email.rb
+++ b/lib/gitlab/private_commit_email.rb
@@ -2,7 +2,7 @@
module Gitlab
module PrivateCommitEmail
- TOKEN = "_private".freeze
+ TOKEN = "_private"
class << self
def regex
diff --git a/lib/gitlab/profiler.rb b/lib/gitlab/profiler.rb
index 425c30d67fe..3f26b84be20 100644
--- a/lib/gitlab/profiler.rb
+++ b/lib/gitlab/profiler.rb
@@ -3,7 +3,7 @@
module Gitlab
module Profiler
- FILTERED_STRING = '[FILTERED]'.freeze
+ FILTERED_STRING = '[FILTERED]'
IGNORE_BACKTRACES = %w[
lib/gitlab/i18n.rb
diff --git a/lib/gitlab/prometheus/additional_metrics_parser.rb b/lib/gitlab/prometheus/additional_metrics_parser.rb
index bd4ca578840..ee3d98f3602 100644
--- a/lib/gitlab/prometheus/additional_metrics_parser.rb
+++ b/lib/gitlab/prometheus/additional_metrics_parser.rb
@@ -3,7 +3,7 @@
module Gitlab
module Prometheus
module AdditionalMetricsParser
- CONFIG_ROOT = 'config/prometheus'.freeze
+ CONFIG_ROOT = 'config/prometheus'
MUTEX = Mutex.new
extend self
diff --git a/lib/gitlab/query_limiting/middleware.rb b/lib/gitlab/query_limiting/middleware.rb
index 949ae79a047..f6ffbfe2645 100644
--- a/lib/gitlab/query_limiting/middleware.rb
+++ b/lib/gitlab/query_limiting/middleware.rb
@@ -5,8 +5,8 @@ module Gitlab
# Middleware for reporting (or raising) when a request performs more than a
# certain amount of database queries.
class Middleware
- CONTROLLER_KEY = 'action_controller.instance'.freeze
- ENDPOINT_KEY = 'api.endpoint'.freeze
+ CONTROLLER_KEY = 'action_controller.instance'
+ ENDPOINT_KEY = 'api.endpoint'
def initialize(app)
@app = app
diff --git a/lib/gitlab/quick_actions/issuable_actions.rb b/lib/gitlab/quick_actions/issuable_actions.rb
index e5d99ebee35..5cf24823ef5 100644
--- a/lib/gitlab/quick_actions/issuable_actions.rb
+++ b/lib/gitlab/quick_actions/issuable_actions.rb
@@ -1,3 +1,4 @@
+# coding: utf-8
# frozen_string_literal: true
module Gitlab
@@ -6,8 +7,8 @@ module Gitlab
extend ActiveSupport::Concern
include Gitlab::QuickActions::Dsl
- SHRUG = '¯\\_(ツ)_/¯'.freeze
- TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
+ SHRUG = '¯\\_(ツ)_/¯'
+ TABLEFLIP = '(╯°□°)╯︵ ┻━┻'
included do
# Issue, MergeRequest, Epic: quick actions definitions
diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb
index da28fbf5be0..869627ac585 100644
--- a/lib/gitlab/quick_actions/issue_actions.rb
+++ b/lib/gitlab/quick_actions/issue_actions.rb
@@ -25,7 +25,11 @@ module Gitlab
Chronic.parse(due_date_param).try(:to_date)
end
command :due do |due_date|
- @updates[:due_date] = due_date if due_date
+ if due_date
+ @updates[:due_date] = due_date
+ else
+ @execution_message[:due] = _('Failed to set due date because the date format is invalid.')
+ end
end
desc _('Remove due date')
diff --git a/lib/gitlab/redis/cache.rb b/lib/gitlab/redis/cache.rb
index 6e8403ad878..6e31c506438 100644
--- a/lib/gitlab/redis/cache.rb
+++ b/lib/gitlab/redis/cache.rb
@@ -6,9 +6,9 @@ require_relative 'wrapper' unless defined?(::Rails) && ::Rails.root.present?
module Gitlab
module Redis
class Cache < ::Gitlab::Redis::Wrapper
- CACHE_NAMESPACE = 'cache:gitlab'.freeze
- DEFAULT_REDIS_CACHE_URL = 'redis://localhost:6380'.freeze
- REDIS_CACHE_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_CACHE_CONFIG_FILE'.freeze
+ CACHE_NAMESPACE = 'cache:gitlab'
+ DEFAULT_REDIS_CACHE_URL = 'redis://localhost:6380'
+ REDIS_CACHE_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_CACHE_CONFIG_FILE'
class << self
def default_url
diff --git a/lib/gitlab/redis/queues.rb b/lib/gitlab/redis/queues.rb
index 8b42c269dd0..0375e4a221a 100644
--- a/lib/gitlab/redis/queues.rb
+++ b/lib/gitlab/redis/queues.rb
@@ -6,10 +6,10 @@ require_relative 'wrapper' unless defined?(::Gitlab::Redis::Wrapper)
module Gitlab
module Redis
class Queues < ::Gitlab::Redis::Wrapper
- SIDEKIQ_NAMESPACE = 'resque:gitlab'.freeze
- MAILROOM_NAMESPACE = 'mail_room:gitlab'.freeze
- DEFAULT_REDIS_QUEUES_URL = 'redis://localhost:6381'.freeze
- REDIS_QUEUES_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_QUEUES_CONFIG_FILE'.freeze
+ SIDEKIQ_NAMESPACE = 'resque:gitlab'
+ MAILROOM_NAMESPACE = 'mail_room:gitlab'
+ DEFAULT_REDIS_QUEUES_URL = 'redis://localhost:6381'
+ REDIS_QUEUES_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_QUEUES_CONFIG_FILE'
class << self
def default_url
diff --git a/lib/gitlab/redis/shared_state.rb b/lib/gitlab/redis/shared_state.rb
index 270a19e780c..35356083f26 100644
--- a/lib/gitlab/redis/shared_state.rb
+++ b/lib/gitlab/redis/shared_state.rb
@@ -6,12 +6,12 @@ require_relative 'wrapper' unless defined?(::Gitlab::Redis::Wrapper)
module Gitlab
module Redis
class SharedState < ::Gitlab::Redis::Wrapper
- SESSION_NAMESPACE = 'session:gitlab'.freeze
- USER_SESSIONS_NAMESPACE = 'session:user:gitlab'.freeze
- USER_SESSIONS_LOOKUP_NAMESPACE = 'session:lookup:user:gitlab'.freeze
- IP_SESSIONS_LOOKUP_NAMESPACE = 'session:lookup:ip:gitlab'.freeze
- DEFAULT_REDIS_SHARED_STATE_URL = 'redis://localhost:6382'.freeze
- REDIS_SHARED_STATE_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_SHARED_STATE_CONFIG_FILE'.freeze
+ SESSION_NAMESPACE = 'session:gitlab'
+ USER_SESSIONS_NAMESPACE = 'session:user:gitlab'
+ USER_SESSIONS_LOOKUP_NAMESPACE = 'session:lookup:user:gitlab'
+ IP_SESSIONS_LOOKUP_NAMESPACE = 'session:lookup:ip:gitlab'
+ DEFAULT_REDIS_SHARED_STATE_URL = 'redis://localhost:6382'
+ REDIS_SHARED_STATE_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_SHARED_STATE_CONFIG_FILE'
class << self
def default_url
diff --git a/lib/gitlab/redis/wrapper.rb b/lib/gitlab/redis/wrapper.rb
index 07a1e20b076..fa1615a5953 100644
--- a/lib/gitlab/redis/wrapper.rb
+++ b/lib/gitlab/redis/wrapper.rb
@@ -8,8 +8,8 @@ require 'active_support/core_ext/module/delegation'
module Gitlab
module Redis
class Wrapper
- DEFAULT_REDIS_URL = 'redis://localhost:6379'.freeze
- REDIS_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_CONFIG_FILE'.freeze
+ DEFAULT_REDIS_URL = 'redis://localhost:6379'
+ REDIS_CONFIG_ENV_VAR_NAME = 'GITLAB_REDIS_CONFIG_FILE'
class << self
delegate :params, :url, to: :new
diff --git a/lib/gitlab/request_profiler.rb b/lib/gitlab/request_profiler.rb
index 033e451dbee..dd1482da40d 100644
--- a/lib/gitlab/request_profiler.rb
+++ b/lib/gitlab/request_profiler.rb
@@ -4,7 +4,7 @@ require 'fileutils'
module Gitlab
module RequestProfiler
- PROFILES_DIR = "#{Gitlab.config.shared.path}/tmp/requests_profiles".freeze
+ PROFILES_DIR = "#{Gitlab.config.shared.path}/tmp/requests_profiles"
def all
Dir["#{PROFILES_DIR}/*.{html,txt}"].map do |path|
diff --git a/lib/gitlab/shard_health_cache.rb b/lib/gitlab/shard_health_cache.rb
index 6612347438e..eeb0cc75ef9 100644
--- a/lib/gitlab/shard_health_cache.rb
+++ b/lib/gitlab/shard_health_cache.rb
@@ -2,7 +2,7 @@
module Gitlab
class ShardHealthCache
- HEALTHY_SHARDS_KEY = 'gitlab-healthy-shards'.freeze
+ HEALTHY_SHARDS_KEY = 'gitlab-healthy-shards'
HEALTHY_SHARDS_TIMEOUT = 300
# Clears the Redis set storing the list of healthy shards
diff --git a/lib/gitlab/sidekiq_monitor.rb b/lib/gitlab/sidekiq_monitor.rb
index 9842f1f53f7..a58b33534bf 100644
--- a/lib/gitlab/sidekiq_monitor.rb
+++ b/lib/gitlab/sidekiq_monitor.rb
@@ -4,7 +4,7 @@ module Gitlab
class SidekiqMonitor < Daemon
include ::Gitlab::Utils::StrongMemoize
- NOTIFICATION_CHANNEL = 'sidekiq:cancel:notifications'.freeze
+ NOTIFICATION_CHANNEL = 'sidekiq:cancel:notifications'
CANCEL_DEADLINE = 24.hours.seconds
RECONNECT_TIME = 3.seconds
diff --git a/lib/gitlab/sidekiq_status.rb b/lib/gitlab/sidekiq_status.rb
index 0f890a12134..0dafccb3d34 100644
--- a/lib/gitlab/sidekiq_status.rb
+++ b/lib/gitlab/sidekiq_status.rb
@@ -18,7 +18,7 @@ module Gitlab
# expire after a certain period of time to prevent storing too many keys in
# Redis.
module SidekiqStatus
- STATUS_KEY = 'gitlab-sidekiq-status:%s'.freeze
+ STATUS_KEY = 'gitlab-sidekiq-status:%s'
# The default time (in seconds) after which a status key is expired
# automatically. The default of 30 minutes should be more than sufficient
diff --git a/lib/gitlab/tracing.rb b/lib/gitlab/tracing.rb
index 29517591c51..7732d7c9d9c 100644
--- a/lib/gitlab/tracing.rb
+++ b/lib/gitlab/tracing.rb
@@ -30,7 +30,7 @@ module Gitlab
# Avoid using `format` since it can throw TypeErrors
# which we want to avoid on unsanitised env var input
tracing_url_template.to_s
- .gsub(/\{\{\s*correlation_id\s*\}\}/, Gitlab::CorrelationId.current_id.to_s)
+ .gsub(/\{\{\s*correlation_id\s*\}\}/, Labkit::Correlation::CorrelationId.current_id.to_s)
.gsub(/\{\{\s*service\s*\}\}/, Gitlab.process_name)
end
end
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
index 9c35d200dcb..fab504aa603 100644
--- a/lib/gitlab/url_blocker.rb
+++ b/lib/gitlab/url_blocker.rb
@@ -49,7 +49,7 @@ module Gitlab
hostname = uri.hostname
port = get_port(uri)
- address_info = get_address_info(hostname, port)
+ address_info = get_address_info(hostname, port, dns_rebind_protection)
return [uri, nil] unless address_info
ip_address = ip_address(address_info)
@@ -110,11 +110,15 @@ module Gitlab
validate_unicode_restriction(uri) if ascii_only
end
- def get_address_info(hostname, port)
+ def get_address_info(hostname, port, dns_rebind_protection)
Addrinfo.getaddrinfo(hostname, port, nil, :STREAM).map do |addr|
addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr
end
rescue SocketError
+ # If the dns rebinding protection is not enabled, we allow
+ # urls that can't be resolved at this point.
+ return unless dns_rebind_protection
+
# In the test suite we use a lot of mocked urls that are either invalid or
# don't exist. In order to avoid modifying a ton of tests and factories
# we allow invalid urls unless the environment variable RSPEC_ALLOW_INVALID_URLS
diff --git a/lib/gitlab/url_helpers.rb b/lib/gitlab/url_helpers.rb
index 883585c196f..2a7919883c5 100644
--- a/lib/gitlab/url_helpers.rb
+++ b/lib/gitlab/url_helpers.rb
@@ -2,7 +2,7 @@
module Gitlab
class UrlHelpers
- WSS_PROTOCOL = "wss".freeze
+ WSS_PROTOCOL = "wss"
def self.as_wss(url)
return unless url.present?
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 29087d26007..db67e4fd479 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -7,17 +7,15 @@ require 'uri'
module Gitlab
class Workhorse
- SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data'.freeze
- VERSION_FILE = 'GITLAB_WORKHORSE_VERSION'.freeze
- INTERNAL_API_CONTENT_TYPE = 'application/vnd.gitlab-workhorse+json'.freeze
- INTERNAL_API_REQUEST_HEADER = 'Gitlab-Workhorse-Api-Request'.freeze
- NOTIFICATION_CHANNEL = 'workhorse:notifications'.freeze
+ SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data'
+ VERSION_FILE = 'GITLAB_WORKHORSE_VERSION'
+ INTERNAL_API_CONTENT_TYPE = 'application/vnd.gitlab-workhorse+json'
+ INTERNAL_API_REQUEST_HEADER = 'Gitlab-Workhorse-Api-Request'
+ NOTIFICATION_CHANNEL = 'workhorse:notifications'
ALLOWED_GIT_HTTP_ACTIONS = %w[git_receive_pack git_upload_pack info_refs].freeze
- DETECT_HEADER = 'Gitlab-Workhorse-Detect-Content-Type'.freeze
+ DETECT_HEADER = 'Gitlab-Workhorse-Detect-Content-Type'
- # Supposedly the effective key size for HMAC-SHA256 is 256 bits, i.e. 32
- # bytes https://tools.ietf.org/html/rfc4868#section-2.6
- SECRET_LENGTH = 32
+ include JwtAuthenticatable
class << self
def git_http_ok(repository, repo_type, user, action, show_all_refs: false)
@@ -187,34 +185,12 @@ module Gitlab
path.readable? ? path.read.chomp : 'unknown'
end
- def secret
- @secret ||= begin
- bytes = Base64.strict_decode64(File.read(secret_path).chomp)
- raise "#{secret_path} does not contain #{SECRET_LENGTH} bytes" if bytes.length != SECRET_LENGTH
-
- bytes
- end
- end
-
- def write_secret
- bytes = SecureRandom.random_bytes(SECRET_LENGTH)
- File.open(secret_path, 'w:BINARY', 0600) do |f|
- f.chmod(0600) # If the file already existed, the '0600' passed to 'open' above was a no-op.
- f.write(Base64.strict_encode64(bytes))
- end
- end
-
def verify_api_request!(request_headers)
decode_jwt(request_headers[INTERNAL_API_REQUEST_HEADER])
end
def decode_jwt(encoded_message)
- JWT.decode(
- encoded_message,
- secret,
- true,
- { iss: 'gitlab-workhorse', verify_iss: true, algorithm: 'HS256' }
- )
+ decode_jwt_for_issuer('gitlab-workhorse', encoded_message)
end
def secret_path
diff --git a/lib/peek/views/active_record.rb b/lib/peek/views/active_record.rb
index bbc9f11e90f..1bb3ddb964a 100644
--- a/lib/peek/views/active_record.rb
+++ b/lib/peek/views/active_record.rb
@@ -5,15 +5,15 @@ module Peek
class ActiveRecord < DetailedView
DEFAULT_THRESHOLDS = {
calls: 100,
- duration: 3,
- individual_call: 1
+ duration: 3000,
+ individual_call: 1000
}.freeze
THRESHOLDS = {
production: {
calls: 100,
- duration: 15,
- individual_call: 5
+ duration: 15000,
+ individual_call: 5000
}
}.freeze
diff --git a/lib/peek/views/gitaly.rb b/lib/peek/views/gitaly.rb
index f669feae254..7dc00b16cc0 100644
--- a/lib/peek/views/gitaly.rb
+++ b/lib/peek/views/gitaly.rb
@@ -5,15 +5,15 @@ module Peek
class Gitaly < DetailedView
DEFAULT_THRESHOLDS = {
calls: 30,
- duration: 1,
- individual_call: 0.5
+ duration: 1000,
+ individual_call: 500
}.freeze
THRESHOLDS = {
production: {
calls: 30,
- duration: 1,
- individual_call: 0.5
+ duration: 1000,
+ individual_call: 500
}
}.freeze
@@ -24,7 +24,7 @@ module Peek
private
def duration
- ::Gitlab::GitalyClient.query_time
+ ::Gitlab::GitalyClient.query_time * 1000
end
def calls
diff --git a/lib/system_check/incoming_email/foreman_configured_check.rb b/lib/system_check/incoming_email/foreman_configured_check.rb
deleted file mode 100644
index 944913087da..00000000000
--- a/lib/system_check/incoming_email/foreman_configured_check.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module SystemCheck
- module IncomingEmail
- class ForemanConfiguredCheck < SystemCheck::BaseCheck
- set_name 'Foreman configured correctly?'
-
- def check?
- path = Rails.root.join('Procfile')
-
- File.exist?(path) && File.read(path) =~ /^mail_room:/
- end
-
- def show_error
- try_fixing_it(
- 'Enable mail_room in your Procfile.'
- )
- for_more_information(
- 'doc/administration/reply_by_email.md'
- )
- fix_and_rerun
- end
- end
- end
-end
diff --git a/lib/system_check/incoming_email_check.rb b/lib/system_check/incoming_email_check.rb
index 155b6547595..e0e1147711c 100644
--- a/lib/system_check/incoming_email_check.rb
+++ b/lib/system_check/incoming_email_check.rb
@@ -14,8 +14,6 @@ module SystemCheck
if Rails.env.production?
checks << SystemCheck::IncomingEmail::InitdConfiguredCheck
checks << SystemCheck::IncomingEmail::MailRoomRunningCheck
- else
- checks << SystemCheck::IncomingEmail::ForemanConfiguredCheck
end
SystemCheck.run('Reply by email', checks)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a1836646b1a..e15000b5184 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1960,7 +1960,10 @@ msgstr ""
msgid "CICD|The Auto DevOps pipeline will run if no alternative CI configuration file is found."
msgstr ""
-msgid "CICD|You must add a %{kubernetes_cluster_start}Kubernetes cluster integration%{kubernetes_cluster_end} to this project with a domain in order for your deployment strategy to work correctly."
+msgid "CICD|You must add a %{base_domain_link_start}base domain%{link_end} to your %{kubernetes_cluster_link_start}Kubernetes cluster%{link_end} in order for your deployment strategy to work."
+msgstr ""
+
+msgid "CICD|You must add a %{kubernetes_cluster_link_start}Kubernetes cluster integration%{link_end} to this project with a domain in order for your deployment strategy to work correctly."
msgstr ""
msgid "CICD|group enabled"
@@ -4981,6 +4984,9 @@ msgstr ""
msgid "Failed to save preferences."
msgstr ""
+msgid "Failed to set due date because the date format is invalid."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -5334,9 +5340,6 @@ msgstr ""
msgid "GitLab.com import"
msgstr ""
-msgid "GitLab’s issue tracker"
-msgstr ""
-
msgid "Gitaly"
msgstr ""
@@ -6586,9 +6589,6 @@ msgstr ""
msgid "Learn more"
msgstr ""
-msgid "Learn more about %{issue_boards_url}, to keep track of issues in multiple lists, using labels, assignees, and milestones. If you’re missing something from issue boards, please create an issue on %{gitlab_issues_url}."
-msgstr ""
-
msgid "Learn more about Auto DevOps"
msgstr ""
@@ -8188,6 +8188,9 @@ msgstr ""
msgid "Pipeline|Coverage"
msgstr ""
+msgid "Pipeline|Detached merge request pipeline"
+msgstr ""
+
msgid "Pipeline|Duration"
msgstr ""
@@ -8197,6 +8200,12 @@ msgstr ""
msgid "Pipeline|Key"
msgstr ""
+msgid "Pipeline|Merge train pipeline"
+msgstr ""
+
+msgid "Pipeline|Merged result pipeline"
+msgstr ""
+
msgid "Pipeline|Pipeline"
msgstr ""
@@ -10876,6 +10885,9 @@ msgstr ""
msgid "Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging."
msgstr ""
+msgid "Star labels to start sorting by priority"
+msgstr ""
+
msgid "Star toggle failed. Try again later."
msgstr ""
@@ -11553,9 +11565,6 @@ msgstr ""
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr ""
-msgid "The tabs below will be removed in a future version"
-msgstr ""
-
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
msgstr ""
@@ -13814,9 +13823,6 @@ msgstr ""
msgid "issue"
msgstr ""
-msgid "issue boards"
-msgstr ""
-
msgid "it is stored externally"
msgstr ""
diff --git a/package.json b/package.json
index 4244dc2d52b..23e611ae6cc 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"scripts": {
- "check-dependencies": "yarn check --integrity",
+ "check-dependencies": "scripts/frontend/check_dependencies.sh",
"clean": "rm -rf public/assets tmp/cache/*-loader",
"dev-server": "NODE_OPTIONS=\"--max-old-space-size=3584\" nodemon -w 'config/webpack.config.js' --exec 'webpack-dev-server --config config/webpack.config.js'",
"eslint": "eslint --max-warnings 0 --report-unused-disable-directives --ext .js,.vue .",
@@ -16,6 +16,7 @@
"karma": "BABEL_ENV=${BABEL_ENV:=karma} karma start --single-run true config/karma.config.js",
"karma-coverage": "BABEL_ENV=coverage karma start --single-run true config/karma.config.js",
"karma-start": "BABEL_ENV=karma karma start config/karma.config.js",
+ "markdownlint": "markdownlint -c .markdownlint.json 'doc/**/*.md'",
"postinstall": "node ./scripts/frontend/postinstall.js",
"prettier-staged": "node ./scripts/frontend/prettier.js check",
"prettier-staged-save": "node ./scripts/frontend/prettier.js save",
@@ -37,7 +38,7 @@
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.5.5",
"@gitlab/svgs": "^1.71.0",
- "@gitlab/ui": "5.20.2",
+ "@gitlab/ui": "5.21.0",
"@gitlab/visual-review-tools": "1.0.1",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
@@ -185,6 +186,7 @@
"karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.2",
+ "markdownlint-cli": "0.18.0",
"md5": "^2.2.1",
"node-sass": "^4.12.0",
"nodemon": "^1.18.9",
diff --git a/scripts/frontend/check_dependencies.sh b/scripts/frontend/check_dependencies.sh
new file mode 100755
index 00000000000..64e7cf9da52
--- /dev/null
+++ b/scripts/frontend/check_dependencies.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+if ! yarn check --integrity 2>&1 > /dev/null
+then
+ echo
+ echo " $(tput setaf 1)yarn check --integrity$(tput sgr0) failed!"
+ echo " Your dependencies probably don't match the yarn.lock file."
+ echo " Please run $(tput setaf 2)yarn install$(tput sgr0) and try again."
+ echo
+ exit 1
+fi
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 4935c1342a3..a9549171b54 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -36,7 +36,7 @@ function previous_deploy_failed() {
return $status
}
-function delete() {
+function delete_release() {
if [ -z "$CI_ENVIRONMENT_SLUG" ]; then
echoerr "No release given, aborting the delete!"
return
@@ -164,7 +164,7 @@ function create_application_secret() {
function download_chart() {
echoinfo "Downloading the GitLab chart..." true
- curl -o gitlab.tar.bz2 "https://gitlab.com/charts/gitlab/-/archive/${GITLAB_HELM_CHART_REF}/gitlab-${GITLAB_HELM_CHART_REF}.tar.bz2"
+ curl --location -o gitlab.tar.bz2 "https://gitlab.com/gitlab-org/charts/gitlab/-/archive/${GITLAB_HELM_CHART_REF}/gitlab-${GITLAB_HELM_CHART_REF}.tar.bz2"
tar -xjf gitlab.tar.bz2
cd "gitlab-${GITLAB_HELM_CHART_REF}"
@@ -193,7 +193,8 @@ function deploy() {
HELM_CMD=$(cat << EOF
helm upgrade --install \
- --atomic \
+ --force \
+ --wait \
--timeout 900 \
--set releaseOverride="$CI_ENVIRONMENT_SLUG" \
--set global.appConfig.enableUsagePing=false \
diff --git a/spec/config/smime_signature_settings_spec.rb b/spec/config/smime_signature_settings_spec.rb
index 4f0c227d866..38f96e9b330 100644
--- a/spec/config/smime_signature_settings_spec.rb
+++ b/spec/config/smime_signature_settings_spec.rb
@@ -1,4 +1,4 @@
-require 'fast_spec_helper'
+require 'spec_helper'
describe SmimeSignatureSettings do
describe '.parse' do
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 45aebd1554c..17964c78e8d 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Projects::BlobController do
include ProjectForksHelper
diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb
index 89857a9d21b..fafcd6927cd 100644
--- a/spec/controllers/sent_notifications_controller_spec.rb
+++ b/spec/controllers/sent_notifications_controller_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe SentNotificationsController do
let(:user) { create(:user) }
diff --git a/spec/factories/milestone_releases.rb b/spec/factories/milestone_releases.rb
new file mode 100644
index 00000000000..08e109480ab
--- /dev/null
+++ b/spec/factories/milestone_releases.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :milestone_release do
+ milestone
+ release
+
+ before(:create, :build) do |mr|
+ project = create(:project)
+ mr.milestone.project = project
+ mr.release.project = project
+ end
+ end
+end
diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
index ca8874a24f9..4c3c0904a06 100644
--- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb
+++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Admin disables Git access protocol', :js do
include StubENV
diff --git a/spec/features/admin/admin_disables_two_factor_spec.rb b/spec/features/admin/admin_disables_two_factor_spec.rb
index 6e6a4964541..7227141168e 100644
--- a/spec/features/admin/admin_disables_two_factor_spec.rb
+++ b/spec/features/admin/admin_disables_two_factor_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Admin disables 2FA for a user' do
it 'successfully', :js do
diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb
index 8c1ec183286..3e8197588ed 100644
--- a/spec/features/admin/admin_uses_repository_checks_spec.rb
+++ b/spec/features/admin/admin_uses_repository_checks_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Admin uses repository checks' do
include StubENV
diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb
index 6e477a93293..0412dc2b69c 100644
--- a/spec/features/boards/add_issues_modal_spec.rb
+++ b/spec/features/boards/add_issues_modal_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Boards add issue modal', :js do
let(:project) { create(:project, :public) }
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 902ecdcd3e8..57dc9de62fb 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Boards', :js do
include DragTo
diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb
index c8ea202169c..62abd914fcb 100644
--- a/spec/features/boards/issue_ordering_spec.rb
+++ b/spec/features/boards/issue_ordering_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Boards', :js do
include DragTo
diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb
index 5f3a2c409ed..6074c559701 100644
--- a/spec/features/boards/keyboard_shortcut_spec.rb
+++ b/spec/features/boards/keyboard_shortcut_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Boards shortcut', :js do
context 'issues are enabled' do
diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb
index 93de2750466..70bc067f79d 100644
--- a/spec/features/boards/modal_filter_spec.rb
+++ b/spec/features/boards/modal_filter_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Boards add issue modal filtering', :js do
let(:project) { create(:project, :public) }
diff --git a/spec/features/boards/multiple_boards_spec.rb b/spec/features/boards/multiple_boards_spec.rb
index 9a2b7a80498..2389707be9c 100644
--- a/spec/features/boards/multiple_boards_spec.rb
+++ b/spec/features/boards/multiple_boards_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Multiple Issue Boards', :js do
set(:user) { create(:user) }
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index abbec0ea810..730887370dd 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Boards new issue', :js do
let(:project) { create(:project, :public) }
@@ -127,4 +127,44 @@ describe 'Issue Boards new issue', :js do
end
end
end
+
+ context 'group boards' do
+ set(:group) { create(:group, :public) }
+ set(:project) { create(:project, namespace: group) }
+ set(:group_board) { create(:board, group: group) }
+ set(:list) { create(:list, board: group_board, position: 0) }
+
+ context 'for unauthorized users' do
+ before do
+ sign_in(user)
+ visit group_board_path(group, group_board)
+ wait_for_requests
+ end
+
+ it 'displays new issue button in open list' do
+ expect(first('.board')).to have_selector('.issue-count-badge-add-button', count: 1)
+ end
+
+ it 'does not display new issue button in label list' do
+ page.within('.board.is-draggable') do
+ expect(page).not_to have_selector('.issue-count-badge-add-button')
+ end
+ end
+ end
+
+ context 'for authorized users' do
+ it 'display new issue button in label list' do
+ project = create(:project, namespace: group)
+ project.add_reporter(user)
+
+ sign_in(user)
+ visit group_board_path(group, group_board)
+ wait_for_requests
+
+ page.within('.board.is-draggable') do
+ expect(page).to have_selector('.issue-count-badge-add-button')
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/boards/reload_boards_on_browser_back_spec.rb b/spec/features/boards/reload_boards_on_browser_back_spec.rb
index 752c8c1052d..6528b8f58bb 100644
--- a/spec/features/boards/reload_boards_on_browser_back_spec.rb
+++ b/spec/features/boards/reload_boards_on_browser_back_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Ensure Boards do not show stale data on browser back', :js do
let(:project) {create(:project, :public)}
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 7ee3a839293..8497eaf102f 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Boards', :js do
include BoardHelpers
diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb
index 264e5e85505..4384a1a9379 100644
--- a/spec/features/boards/sub_group_project_spec.rb
+++ b/spec/features/boards/sub_group_project_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Sub-group project issue boards', :js do
let(:group) { create(:group) }
diff --git a/spec/features/commits/user_uses_quick_actions_spec.rb b/spec/features/commits/user_uses_quick_actions_spec.rb
index 4b7e7465df1..70ea920b7ec 100644
--- a/spec/features/commits/user_uses_quick_actions_spec.rb
+++ b/spec/features/commits/user_uses_quick_actions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Commit > User uses quick actions', :js do
include Spec::Support::Helpers::Features::NotesHelpers
diff --git a/spec/features/dashboard/todos/target_state_spec.rb b/spec/features/dashboard/todos/target_state_spec.rb
index 931fc16a5eb..0ea1f43e34b 100644
--- a/spec/features/dashboard/todos/target_state_spec.rb
+++ b/spec/features/dashboard/todos/target_state_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Dashboard > Todo target states' do
let(:user) { create(:user) }
diff --git a/spec/features/groups/board_sidebar_spec.rb b/spec/features/groups/board_sidebar_spec.rb
index 9f597efa7b7..ed874141ef4 100644
--- a/spec/features/groups/board_sidebar_spec.rb
+++ b/spec/features/groups/board_sidebar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Group Issue Boards', :js do
include BoardHelpers
diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb
index ca33dbb7a33..f95e2e91cd7 100644
--- a/spec/features/groups/board_spec.rb
+++ b/spec/features/groups/board_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Group Boards' do
let(:group) { create(:group) }
diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb
index 7f0155b63e0..17738905e8d 100644
--- a/spec/features/groups/milestone_spec.rb
+++ b/spec/features/groups/milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Group milestones' do
let(:group) { create(:group) }
diff --git a/spec/features/groups/user_browse_projects_group_page_spec.rb b/spec/features/groups/user_browse_projects_group_page_spec.rb
index 075bc1128ca..68221e3fefe 100644
--- a/spec/features/groups/user_browse_projects_group_page_spec.rb
+++ b/spec/features/groups/user_browse_projects_group_page_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User browse group projects page' do
let(:user) { create :user }
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index bcd2b90d3bb..88a7aa51326 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -58,7 +58,7 @@ describe 'Help Pages' do
before do
stub_application_setting(version_check_enabled: true)
- allow(Rails.env).to receive(:production?).and_return(true)
+ stub_rails_env('production')
allow(VersionCheck).to receive(:url).and_return('/version-check-url')
sign_in(create(:user))
diff --git a/spec/features/instance_statistics/cohorts_spec.rb b/spec/features/instance_statistics/cohorts_spec.rb
index 61294ec9af2..3940e8fa389 100644
--- a/spec/features/instance_statistics/cohorts_spec.rb
+++ b/spec/features/instance_statistics/cohorts_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Cohorts page' do
before do
diff --git a/spec/features/instance_statistics/instance_statistics_spec.rb b/spec/features/instance_statistics/instance_statistics_spec.rb
index 40d0f1db207..0fb78c6eef8 100644
--- a/spec/features/instance_statistics/instance_statistics_spec.rb
+++ b/spec/features/instance_statistics/instance_statistics_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Cohorts page', :js do
before do
diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb
index dc68e633e27..30c516459c5 100644
--- a/spec/features/issuables/issuable_list_spec.rb
+++ b/spec/features/issuables/issuable_list_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'issuable list' do
let(:project) { create(:project) }
diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb
index e84629dc17f..f3b534bca49 100644
--- a/spec/features/issuables/markdown_references/internal_references_spec.rb
+++ b/spec/features/issuables/markdown_references/internal_references_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "rails_helper"
+require 'spec_helper'
describe "Internal references", :js do
include Spec::Support::Helpers::Features::NotesHelpers
diff --git a/spec/features/issuables/markdown_references/jira_spec.rb b/spec/features/issuables/markdown_references/jira_spec.rb
index aecdeffe4a4..8085918f533 100644
--- a/spec/features/issuables/markdown_references/jira_spec.rb
+++ b/spec/features/issuables/markdown_references/jira_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "rails_helper"
+require 'spec_helper'
describe "Jira", :js do
let(:user) { create(:user) }
diff --git a/spec/features/issuables/user_sees_sidebar_spec.rb b/spec/features/issuables/user_sees_sidebar_spec.rb
index d1e10c70414..52040eb8cbb 100644
--- a/spec/features/issuables/user_sees_sidebar_spec.rb
+++ b/spec/features/issuables/user_sees_sidebar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Sidebar on Mobile' do
include MobileHelpers
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb
index e8b828bd264..57d04f0bf40 100644
--- a/spec/features/issues/bulk_assignment_labels_spec.rb
+++ b/spec/features/issues/bulk_assignment_labels_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issues > Labels bulk assignment' do
let(:user) { create(:user) }
diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
index f2e482faf5f..7d3df711555 100644
--- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Resolving all open threads in a merge request from an issue', :js do
let(:user) { create(:user) }
diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
index 08c98358544..8f4083533b3 100644
--- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Resolve an open thread in a merge request by creating an issue', :js do
let(:user) { create(:user) }
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 2ca551cec77..e1177bedd2d 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Dropdown assignee', :js do
include FilteredSearchHelpers
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index b2905fc1dde..bd22eb1056b 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Dropdown author', :js do
include FilteredSearchHelpers
diff --git a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb
index 45344aeb8f5..7ec3d215fb1 100644
--- a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Dropdown emoji', :js do
include FilteredSearchHelpers
diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
index 34313553b34..1c56902a27d 100644
--- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Dropdown hint', :js do
include FilteredSearchHelpers
diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
index 8429fe44c43..9a782950bf6 100644
--- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Dropdown milestone', :js do
include FilteredSearchHelpers
diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb
index 0fe03160e7a..e97314e02e6 100644
--- a/spec/features/issues/filtered_search/search_bar_spec.rb
+++ b/spec/features/issues/filtered_search/search_bar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Search bar', :js do
include FilteredSearchHelpers
diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb
index b20add1ea33..f8035ef4b85 100644
--- a/spec/features/issues/filtered_search/visual_tokens_spec.rb
+++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Visual tokens', :js do
include FilteredSearchHelpers
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index e840ac79916..8d7b6be5ea2 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'New/edit issue', :js do
include ActionView::Helpers::JavaScriptHelper
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 566441dc6f6..cc834df367b 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'GFM autocomplete', :js do
let(:issue_xss_title) { 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
diff --git a/spec/features/issues/group_label_sidebar_spec.rb b/spec/features/issues/group_label_sidebar_spec.rb
index 746c55b6a26..fe6d95e1039 100644
--- a/spec/features/issues/group_label_sidebar_spec.rb
+++ b/spec/features/issues/group_label_sidebar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Group label on issue' do
it 'renders link to the project issues page' do
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb
index 8f2e5b237ea..a1b53718577 100644
--- a/spec/features/issues/issue_detail_spec.rb
+++ b/spec/features/issues/issue_detail_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Detail', :js do
let(:user) { create(:user) }
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index b88d1bbeae5..9baba80bf06 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue Sidebar' do
include MobileHelpers
diff --git a/spec/features/issues/keyboard_shortcut_spec.rb b/spec/features/issues/keyboard_shortcut_spec.rb
index e1325e63e6b..c5d53cd1cd0 100644
--- a/spec/features/issues/keyboard_shortcut_spec.rb
+++ b/spec/features/issues/keyboard_shortcut_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issues shortcut', :js do
context 'New Issue shortcut' do
diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb
index b80b47a4c99..d174fdcb25e 100644
--- a/spec/features/issues/markdown_toolbar_spec.rb
+++ b/spec/features/issues/markdown_toolbar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Issue markdown toolbar', :js do
let(:project) { create(:project, :public) }
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index 9e0be7d8935..1122504248f 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'issue move to another project' do
let(:user) { create(:user) }
diff --git a/spec/features/issues/resource_label_events_spec.rb b/spec/features/issues/resource_label_events_spec.rb
index 3d380c183ec..b367bbe2c99 100644
--- a/spec/features/issues/resource_label_events_spec.rb
+++ b/spec/features/issues/resource_label_events_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'List issue resource label events', :js do
let(:user) { create(:user) }
diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb
index 85c72c42f45..0d009f47fff 100644
--- a/spec/features/issues/spam_issues_spec.rb
+++ b/spec/features/issues/spam_issues_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'New issue', :js do
include StubENV
diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb
index 9282c31751a..4bb96ad069c 100644
--- a/spec/features/issues/todo_spec.rb
+++ b/spec/features/issues/todo_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Manually create a todo item from issue', :js do
let!(:project) { create(:project) }
diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb
index 0e27d0231d0..45a0b1932a2 100644
--- a/spec/features/issues/update_issues_spec.rb
+++ b/spec/features/issues/update_issues_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Multiple issue updating from issues#index', :js do
let!(:project) { create(:project) }
diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
index 878a73718d7..be31c45b373 100644
--- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User creates branch and merge request on issue page', :js do
let(:membership_level) { :developer }
diff --git a/spec/features/issues/user_creates_confidential_merge_request_spec.rb b/spec/features/issues/user_creates_confidential_merge_request_spec.rb
index 4a32b7e2b73..24089bdeb81 100644
--- a/spec/features/issues/user_creates_confidential_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_confidential_merge_request_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User creates confidential merge request on issue page', :js do
include ProjectForksHelper
diff --git a/spec/features/issues/user_sees_breadcrumb_links_spec.rb b/spec/features/issues/user_sees_breadcrumb_links_spec.rb
index db8d3c5dd53..f31d730c337 100644
--- a/spec/features/issues/user_sees_breadcrumb_links_spec.rb
+++ b/spec/features/issues/user_sees_breadcrumb_links_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'New issue breadcrumb' do
let(:project) { create(:project) }
diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb
index 8fec92031a9..26979e943d0 100644
--- a/spec/features/issues/user_uses_quick_actions_spec.rb
+++ b/spec/features/issues/user_uses_quick_actions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
# These are written as feature specs because they cover more specific test scenarios
# than the ones described on spec/services/notes/create_service_spec.rb for quick actions,
diff --git a/spec/features/merge_request/user_assigns_themselves_spec.rb b/spec/features/merge_request/user_assigns_themselves_spec.rb
index d7918a9e9d7..549d6e50337 100644
--- a/spec/features/merge_request/user_assigns_themselves_spec.rb
+++ b/spec/features/merge_request/user_assigns_themselves_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User assigns themselves' do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_awards_emoji_spec.rb b/spec/features/merge_request/user_awards_emoji_spec.rb
index 5e9b232760b..8aa90107251 100644
--- a/spec/features/merge_request/user_awards_emoji_spec.rb
+++ b/spec/features/merge_request/user_awards_emoji_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User awards emoji', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_creates_mr_spec.rb b/spec/features/merge_request/user_creates_mr_spec.rb
index 267097bd466..665bc352c0f 100644
--- a/spec/features/merge_request/user_creates_mr_spec.rb
+++ b/spec/features/merge_request/user_creates_mr_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User creates MR' do
include ProjectForksHelper
diff --git a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb
index 3213efcb60b..895cbb8f02b 100644
--- a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb
+++ b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request < User customizes merge commit message', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_locks_discussion_spec.rb b/spec/features/merge_request/user_locks_discussion_spec.rb
index 365e9b60d90..0eaaf32dc31 100644
--- a/spec/features/merge_request/user_locks_discussion_spec.rb
+++ b/spec/features/merge_request/user_locks_discussion_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User locks discussion', :js do
let(:user) { create(:user) }
diff --git a/spec/features/merge_request/user_merges_immediately_spec.rb b/spec/features/merge_request/user_merges_immediately_spec.rb
index 2f01971c2e9..1188d3b2ceb 100644
--- a/spec/features/merge_request/user_merges_immediately_spec.rb
+++ b/spec/features/merge_request/user_merges_immediately_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge requests > User merges immediately', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
index 3f9c27bbf9d..4afbf30ece4 100644
--- a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User merges only if pipeline succeeds', :js do
let(:merge_request) { create(:merge_request_with_diffs) }
diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
index 93938ac221a..ffc12ffdbaf 100644
--- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User merges when pipeline succeeds', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb
index abae6ffbd71..8b16760606c 100644
--- a/spec/features/merge_request/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User posts diff notes', :js do
include MergeRequestDiffHelpers
diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb
index 1fad9eac1bd..435b3cd2555 100644
--- a/spec/features/merge_request/user_posts_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_notes_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User posts notes', :js do
include NoteInteractionHelpers
diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb
index fb089a9ffcb..dd1ec17ae51 100644
--- a/spec/features/merge_request/user_resolves_conflicts_spec.rb
+++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User resolves conflicts', :js do
let(:project) { create(:project, :repository) }
diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
index b8e4852a748..8b41ef86791 100644
--- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
+++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User resolves diff notes and threads', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
index 23b37c218e1..48c3ed7178d 100644
--- a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
+++ b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User scrolls to note on load', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb
index fae81758086..baef831c40e 100644
--- a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees avatars on diff notes', :js do
include NoteInteractionHelpers
diff --git a/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb b/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb
index e1f0ddc4c6a..592ad3aae9b 100644
--- a/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb
+++ b/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'New merge request breadcrumb' do
let(:project) { create(:project, :repository) }
diff --git a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
index 93ae408a173..f54161fbaec 100644
--- a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
+++ b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees check out branch modal', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb
index 8a2614c53af..1d62f7f0702 100644
--- a/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb
+++ b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User cherry-picks', :js do
let(:group) { create(:group) }
diff --git a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb
index 52163571175..f77ea82649c 100644
--- a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb
+++ b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees closing issues message', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
index f46921af1cd..224261dec00 100644
--- a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
+++ b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees deleted target branch', :js do
let(:merge_request) { create(:merge_request) }
diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
index 14fbfc2fd3f..87fb3f5b3e7 100644
--- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees deployment widget', :js do
describe 'when merge request has associated environments' do
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index 32429bac5f9..8eeed7b0843 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees diff', :js do
include ProjectForksHelper
diff --git a/spec/features/merge_request/user_sees_discussions_spec.rb b/spec/features/merge_request/user_sees_discussions_spec.rb
index a11baf1dca3..48f5814322a 100644
--- a/spec/features/merge_request/user_sees_discussions_spec.rb
+++ b/spec/features/merge_request/user_sees_discussions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees threads', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_sees_empty_state_spec.rb b/spec/features/merge_request/user_sees_empty_state_spec.rb
index f1ad5c2dffc..88eba976d62 100644
--- a/spec/features/merge_request/user_sees_empty_state_spec.rb
+++ b/spec/features/merge_request/user_sees_empty_state_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees empty state' do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
index 53cafb60dfb..4cc129e5d5f 100644
--- a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees merge button depending on unresolved threads', :js do
let(:project) { create(:project, :repository) }
diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
index 28f88718ec1..dd5662d83f2 100644
--- a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees pipelines triggered by merge request', :js do
include ProjectForksHelper
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index b5d0240e9de..3f2a676462b 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees merge widget', :js do
include ProjectForksHelper
diff --git a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
index eb89d616b14..4d801c6ff11 100644
--- a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
+++ b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request < User sees mini pipeline graph', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb b/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb
index 80ee35f2a91..b4fb844b943 100644
--- a/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb
+++ b/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees MR from deleted forked project', :js do
include ProjectForksHelper
diff --git a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb
index d9dc32d0594..db0d632cdf2 100644
--- a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb
+++ b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
# This test serves as a regression test for a bug that caused an error
# message to be shown by JavaScript when the source branch was deleted.
diff --git a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb
index 195592531f2..0391794649c 100644
--- a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb
+++ b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees notes from forked project', :js do
include ProjectForksHelper
diff --git a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb
index 68c9e0b123d..3e15a9c136b 100644
--- a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees pipelines from forked project', :js do
include ProjectForksHelper
diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb
index e057f59e00c..f04317a59ee 100644
--- a/spec/features/merge_request/user_sees_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees pipelines', :js do
describe 'pipeline tab' do
diff --git a/spec/features/merge_request/user_sees_system_notes_spec.rb b/spec/features/merge_request/user_sees_system_notes_spec.rb
index 26cdd5ba21c..0482458d5ac 100644
--- a/spec/features/merge_request/user_sees_system_notes_spec.rb
+++ b/spec/features/merge_request/user_sees_system_notes_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees system notes', :js do
let(:public_project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb
index dae5845adec..62abcff7bda 100644
--- a/spec/features/merge_request/user_sees_versions_spec.rb
+++ b/spec/features/merge_request/user_sees_versions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees versions', :js do
let(:merge_request) do
diff --git a/spec/features/merge_request/user_sees_wip_help_message_spec.rb b/spec/features/merge_request/user_sees_wip_help_message_spec.rb
index 46209237faf..1179303171c 100644
--- a/spec/features/merge_request/user_sees_wip_help_message_spec.rb
+++ b/spec/features/merge_request/user_sees_wip_help_message_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees WIP help message' do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
index a1f027cbb1d..6262f1ce055 100644
--- a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
+++ b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User selects branches for new MR', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb
index 61b9904dde5..4db067a4e41 100644
--- a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb
+++ b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User toggles whitespace changes', :js do
let(:merge_request) { create(:merge_request) }
diff --git a/spec/features/merge_request/user_uses_quick_actions_spec.rb b/spec/features/merge_request/user_uses_quick_actions_spec.rb
index 3948c0c5c89..318f8812263 100644
--- a/spec/features/merge_request/user_uses_quick_actions_spec.rb
+++ b/spec/features/merge_request/user_uses_quick_actions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
# These are written as feature specs because they cover more specific test scenarios
# than the ones described on spec/services/notes/create_service_spec.rb for quick actions,
diff --git a/spec/features/merge_requests/filters_generic_behavior_spec.rb b/spec/features/merge_requests/filters_generic_behavior_spec.rb
index 404e591cf4b..58aad1b7e91 100644
--- a/spec/features/merge_requests/filters_generic_behavior_spec.rb
+++ b/spec/features/merge_requests/filters_generic_behavior_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge Requests > Filters generic behavior', :js do
include FilteredSearchHelpers
diff --git a/spec/features/merge_requests/user_filters_by_assignees_spec.rb b/spec/features/merge_requests/user_filters_by_assignees_spec.rb
index b896b6392f1..00bd8455ae1 100644
--- a/spec/features/merge_requests/user_filters_by_assignees_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_assignees_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge Requests > User filters by assignees', :js do
include FilteredSearchHelpers
diff --git a/spec/features/merge_requests/user_filters_by_labels_spec.rb b/spec/features/merge_requests/user_filters_by_labels_spec.rb
index 9fb149ca58d..fd2b4b23f96 100644
--- a/spec/features/merge_requests/user_filters_by_labels_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_labels_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge Requests > User filters by labels', :js do
include FilteredSearchHelpers
diff --git a/spec/features/merge_requests/user_filters_by_milestones_spec.rb b/spec/features/merge_requests/user_filters_by_milestones_spec.rb
index 2fb3c86ea94..e0ee69d7a5b 100644
--- a/spec/features/merge_requests/user_filters_by_milestones_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_milestones_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge Requests > User filters by milestones', :js do
include FilteredSearchHelpers
diff --git a/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb b/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb
index 3dd0f93ddfa..bc6e2ac5132 100644
--- a/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge requests > User filters by multiple criteria', :js do
include FilteredSearchHelpers
diff --git a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
index b5969f656b0..0d03c5eae31 100644
--- a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge Requests > User filters by target branch', :js do
include FilteredSearchHelpers
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
index 69d4650d1ac..f145bdd044b 100644
--- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge requests > User lists merge requests' do
include MergeRequestHelpers
diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb
index 48c92a87c63..4d3461bf1ae 100644
--- a/spec/features/merge_requests/user_mass_updates_spec.rb
+++ b/spec/features/merge_requests/user_mass_updates_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge requests > User mass updates', :js do
let(:project) { create(:project, :repository) }
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index 6d5acc894b1..bfff33f3956 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Milestone' do
let(:group) { create(:group, :public) }
diff --git a/spec/features/milestones/user_creates_milestone_spec.rb b/spec/features/milestones/user_creates_milestone_spec.rb
index 73f4f187501..5c93ddcf6f8 100644
--- a/spec/features/milestones/user_creates_milestone_spec.rb
+++ b/spec/features/milestones/user_creates_milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "rails_helper"
+require 'spec_helper'
describe "User creates milestone", :js do
set(:user) { create(:user) }
diff --git a/spec/features/milestones/user_deletes_milestone_spec.rb b/spec/features/milestones/user_deletes_milestone_spec.rb
index 5666c1dd507..7c1d88f7798 100644
--- a/spec/features/milestones/user_deletes_milestone_spec.rb
+++ b/spec/features/milestones/user_deletes_milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "rails_helper"
+require 'spec_helper'
describe "User deletes milestone", :js do
let(:user) { create(:user) }
diff --git a/spec/features/milestones/user_edits_milestone_spec.rb b/spec/features/milestones/user_edits_milestone_spec.rb
index f8e96eac3ea..b41b8f3282f 100644
--- a/spec/features/milestones/user_edits_milestone_spec.rb
+++ b/spec/features/milestones/user_edits_milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "rails_helper"
+require 'spec_helper'
describe "User edits milestone", :js do
set(:user) { create(:user) }
diff --git a/spec/features/milestones/user_promotes_milestone_spec.rb b/spec/features/milestones/user_promotes_milestone_spec.rb
index acceb5cad62..7678b6cbfa5 100644
--- a/spec/features/milestones/user_promotes_milestone_spec.rb
+++ b/spec/features/milestones/user_promotes_milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User promotes milestone' do
set(:group) { create(:group) }
diff --git a/spec/features/milestones/user_sees_breadcrumb_links_spec.rb b/spec/features/milestones/user_sees_breadcrumb_links_spec.rb
index f58242759cc..92445735328 100644
--- a/spec/features/milestones/user_sees_breadcrumb_links_spec.rb
+++ b/spec/features/milestones/user_sees_breadcrumb_links_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'New project milestone breadcrumb' do
let(:project) { create(:project) }
diff --git a/spec/features/milestones/user_views_milestone_spec.rb b/spec/features/milestones/user_views_milestone_spec.rb
index aa0cdf66b75..71abb195ad1 100644
--- a/spec/features/milestones/user_views_milestone_spec.rb
+++ b/spec/features/milestones/user_views_milestone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "rails_helper"
+require 'spec_helper'
describe "User views milestone" do
set(:user) { create(:user) }
diff --git a/spec/features/milestones/user_views_milestones_spec.rb b/spec/features/milestones/user_views_milestones_spec.rb
index 6868791f584..0b51ca12997 100644
--- a/spec/features/milestones/user_views_milestones_spec.rb
+++ b/spec/features/milestones/user_views_milestones_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "rails_helper"
+require 'spec_helper'
describe "User views milestones" do
set(:user) { create(:user) }
diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb
index 741e41adbf1..c6db15065f2 100644
--- a/spec/features/profiles/account_spec.rb
+++ b/spec/features/profiles/account_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Profile > Account', :js do
let(:user) { create(:user, username: 'foo') }
diff --git a/spec/features/profiles/active_sessions_spec.rb b/spec/features/profiles/active_sessions_spec.rb
index 709cca7d178..a5c2d15f598 100644
--- a/spec/features/profiles/active_sessions_spec.rb
+++ b/spec/features/profiles/active_sessions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do
let(:user) do
diff --git a/spec/features/profiles/chat_names_spec.rb b/spec/features/profiles/chat_names_spec.rb
index 0219dacbc38..4c447faf77e 100644
--- a/spec/features/profiles/chat_names_spec.rb
+++ b/spec/features/profiles/chat_names_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Profile > Chat' do
let(:user) { create(:user) }
diff --git a/spec/features/profiles/emails_spec.rb b/spec/features/profiles/emails_spec.rb
index 40e2988730b..4d2cd0f8b56 100644
--- a/spec/features/profiles/emails_spec.rb
+++ b/spec/features/profiles/emails_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Profile > Emails' do
let(:user) { create(:user) }
diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb
index 4237f037c27..07e87f36c65 100644
--- a/spec/features/profiles/gpg_keys_spec.rb
+++ b/spec/features/profiles/gpg_keys_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Profile > GPG Keys' do
let(:user) { create(:user, email: GpgHelpers::User2.emails.first) }
diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb
index c1b142c4e12..3fc0fd76d2e 100644
--- a/spec/features/profiles/keys_spec.rb
+++ b/spec/features/profiles/keys_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Profile > SSH Keys' do
let(:user) { create(:user) }
diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
index 1199a3bd226..3d9fcfe0f62 100644
--- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb
+++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Mini Pipeline Graph in Commit View', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb b/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb
index 35c84204910..68a924e4fad 100644
--- a/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb
+++ b/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'New project label breadcrumb' do
let(:project) { create(:project) }
diff --git a/spec/features/projects/settings/lfs_settings_spec.rb b/spec/features/projects/settings/lfs_settings_spec.rb
index 56606df5a78..5fa3b9bba55 100644
--- a/spec/features/projects/settings/lfs_settings_spec.rb
+++ b/spec/features/projects/settings/lfs_settings_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Projects > Settings > LFS settings' do
let(:project) { create(:project) }
diff --git a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb
index 9c77a08718e..3e9bfed1e47 100644
--- a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb
+++ b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Repository Settings > User sees revoke deploy token modal', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb
index 6f176c260a2..70dc6c966ba 100644
--- a/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb
+++ b/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Projects > Show > Developer views empty project instructions' do
let(:project) { create(:project, :empty_repo) }
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index 430883fdf29..891b780a100 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Projects > Snippets > Create Snippet', :js do
include DropzoneHelper
diff --git a/spec/features/projects/tags/user_edits_tags_spec.rb b/spec/features/projects/tags/user_edits_tags_spec.rb
index ebb2844d17f..63f97eeb4e0 100644
--- a/spec/features/projects/tags/user_edits_tags_spec.rb
+++ b/spec/features/projects/tags/user_edits_tags_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Project > Tags', :js do
include DropzoneHelper
diff --git a/spec/features/read_only_spec.rb b/spec/features/read_only_spec.rb
index 3af4b51b9b1..619d34ebed4 100644
--- a/spec/features/read_only_spec.rb
+++ b/spec/features/read_only_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'read-only message' do
set(:user) { create(:user) }
diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb
index f4f3872aa09..d6575ec9de1 100644
--- a/spec/features/security/group/internal_access_spec.rb
+++ b/spec/features/security/group/internal_access_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Internal Group access' do
include AccessMatchers
diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb
index 9cef8ef777c..2dc863a6e73 100644
--- a/spec/features/security/group/private_access_spec.rb
+++ b/spec/features/security/group/private_access_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Private Group access' do
include AccessMatchers
diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb
index bbe74f0dab0..4066a19fce2 100644
--- a/spec/features/security/group/public_access_spec.rb
+++ b/spec/features/security/group/public_access_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Public Group access' do
include AccessMatchers
diff --git a/spec/features/snippets/explore_spec.rb b/spec/features/snippets/explore_spec.rb
index b48a5691e96..57e91fea709 100644
--- a/spec/features/snippets/explore_spec.rb
+++ b/spec/features/snippets/explore_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Explore Snippets' do
let!(:public_snippet) { create(:personal_snippet, :public) }
diff --git a/spec/features/snippets/internal_snippet_spec.rb b/spec/features/snippets/internal_snippet_spec.rb
index 8454a347382..4ef3b0e5e7a 100644
--- a/spec/features/snippets/internal_snippet_spec.rb
+++ b/spec/features/snippets/internal_snippet_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Internal Snippets', :js do
let(:internal_snippet) { create(:personal_snippet, :internal) }
diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb
index e32a9292e22..a0db00cfc67 100644
--- a/spec/features/snippets/public_snippets_spec.rb
+++ b/spec/features/snippets/public_snippets_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Public Snippets', :js do
it 'Unauthenticated user should see public snippets' do
diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb
index bbdf544bd0c..dce790e5708 100644
--- a/spec/features/snippets/search_snippets_spec.rb
+++ b/spec/features/snippets/search_snippets_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Search Snippets' do
it 'User searches for snippets by title' do
diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb
index a4a5407d1f7..52ec5eddd5c 100644
--- a/spec/features/snippets/user_creates_snippet_spec.rb
+++ b/spec/features/snippets/user_creates_snippet_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User creates snippet', :js do
include DropzoneHelper
diff --git a/spec/features/snippets/user_deletes_snippet_spec.rb b/spec/features/snippets/user_deletes_snippet_spec.rb
index 9773aca849a..217419a220a 100644
--- a/spec/features/snippets/user_deletes_snippet_spec.rb
+++ b/spec/features/snippets/user_deletes_snippet_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User deletes snippet' do
let(:user) { create(:user) }
diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb
index 5ff12c37aff..51d9baf44bc 100644
--- a/spec/features/snippets/user_edits_snippet_spec.rb
+++ b/spec/features/snippets/user_edits_snippet_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User edits snippet', :js do
include DropzoneHelper
diff --git a/spec/features/snippets/user_snippets_spec.rb b/spec/features/snippets/user_snippets_spec.rb
index 4e9215db945..c6daa19d5e6 100644
--- a/spec/features/snippets/user_snippets_spec.rb
+++ b/spec/features/snippets/user_snippets_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User Snippets' do
let(:author) { create(:user) }
diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
index 40d864e0002..d9d9d7e4b04 100644
--- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User uploads avatar to group' do
it 'they see the new avatar' do
diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
index 4c694365e3b..fc31d7aa3d1 100644
--- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User uploads avatar to profile' do
let!(:user) { create(:user) }
diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb
index 6bf8e8ea74f..30b5cf267ae 100644
--- a/spec/features/uploads/user_uploads_file_to_note_spec.rb
+++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User uploads file to note' do
include DropzoneHelper
diff --git a/spec/features/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb
index b2036108d42..8b3f193f418 100644
--- a/spec/features/user_can_display_performance_bar_spec.rb
+++ b/spec/features/user_can_display_performance_bar_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'User can display performance bar', :js do
shared_examples 'performance bar cannot be displayed' do
@@ -37,7 +37,7 @@ describe 'User can display performance bar', :js do
shared_examples 'performance bar is enabled by default in development' do
before do
- allow(Rails.env).to receive(:development?).and_return(true)
+ stub_rails_env('development')
end
it 'shows the performance bar by default' do
diff --git a/spec/features/user_sees_revert_modal_spec.rb b/spec/features/user_sees_revert_modal_spec.rb
index 35828b5f086..24b4f8dd4aa 100644
--- a/spec/features/user_sees_revert_modal_spec.rb
+++ b/spec/features/user_sees_revert_modal_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'Merge request > User sees revert modal', :js do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/fixtures/api/schemas/pipeline.json b/spec/fixtures/api/schemas/pipeline.json
index b6e30c40f13..d9ffad8fbab 100644
--- a/spec/fixtures/api/schemas/pipeline.json
+++ b/spec/fixtures/api/schemas/pipeline.json
@@ -97,6 +97,10 @@
"id": "/properties/details/properties/finished_at",
"type": "string"
},
+ "name": {
+ "id": "/properties/details/properties/name",
+ "type": "string"
+ },
"manual_actions": {
"id": "/properties/details/properties/manual_actions",
"items": {},
@@ -323,6 +327,10 @@
"id": "/properties/web_url",
"type": "string"
},
+ "merge_request_event_type": {
+ "id": "/properties/merge_request_event_type",
+ "type": "string"
+ },
"user": {
"id": "/properties/user",
"properties": {
diff --git a/spec/fixtures/api/schemas/public_api/v4/release.json b/spec/fixtures/api/schemas/public_api/v4/release.json
index ec3fa59cdb1..078b1c0b982 100644
--- a/spec/fixtures/api/schemas/public_api/v4/release.json
+++ b/spec/fixtures/api/schemas/public_api/v4/release.json
@@ -15,6 +15,7 @@
"author": {
"oneOf": [{ "type": "null" }, { "$ref": "user/basic.json" }]
},
+ "milestone": { "type": "string" },
"assets": {
"required": ["count", "links", "sources"],
"properties": {
diff --git a/spec/frontend/branches/divergence_graph_spec.js b/spec/frontend/branches/divergence_graph_spec.js
index 8283bc966e4..adf39a2216a 100644
--- a/spec/frontend/branches/divergence_graph_spec.js
+++ b/spec/frontend/branches/divergence_graph_spec.js
@@ -25,13 +25,25 @@ describe('Divergence graph', () => {
mock.restore();
});
- it('calls axos get with list of branch names', () =>
+ it('calls axios get with list of branch names', () =>
init('/-/diverging_counts').then(() => {
expect(axios.get).toHaveBeenCalledWith('/-/diverging_counts', {
params: { names: ['master', 'test/hello-world'] },
});
}));
+ describe('no branches listed', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `<div></div>`;
+ });
+
+ it('avoids requesting diverging commit counts', () => {
+ expect(axios.get).not.toHaveBeenCalledWith('/-/diverging_counts');
+
+ init('/-/diverging_counts');
+ });
+ });
+
it('creates Vue components', () =>
init('/-/diverging_counts').then(() => {
expect(document.querySelector('[data-name="master"]').innerHTML).not.toEqual('');
diff --git a/spec/frontend/clusters/stores/clusters_store_spec.js b/spec/frontend/clusters/stores/clusters_store_spec.js
index c168bce7a4e..98077498998 100644
--- a/spec/frontend/clusters/stores/clusters_store_spec.js
+++ b/spec/frontend/clusters/stores/clusters_store_spec.js
@@ -51,6 +51,9 @@ describe('Clusters Store', () => {
expect(store.state).toEqual({
helpPath: null,
ingressHelpPath: null,
+ environmentsHelpPath: null,
+ clustersHelpPath: null,
+ deployBoardsHelpPath: null,
status: mockResponseData.status,
statusReason: mockResponseData.status_reason,
rbac: false,
@@ -148,6 +151,7 @@ describe('Clusters Store', () => {
uninstallFailed: false,
},
},
+ environments: [],
});
});
diff --git a/spec/frontend/jobs/store/utils_spec.js b/spec/frontend/jobs/store/utils_spec.js
new file mode 100644
index 00000000000..9e81558f8c2
--- /dev/null
+++ b/spec/frontend/jobs/store/utils_spec.js
@@ -0,0 +1,60 @@
+import linesParser from '~/jobs/store/utils';
+
+describe('linesParser', () => {
+ const mockData = [
+ {
+ offset: 1001,
+ content: [{ text: ' on docker-auto-scale-com 8a6210b8' }],
+ },
+ {
+ offset: 1002,
+ content: [
+ {
+ text:
+ 'Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33',
+ },
+ ],
+ sections: ['prepare-executor'],
+ section_header: true,
+ },
+ {
+ offset: 1003,
+ content: [{ text: 'Starting service postgres:9.6.14 ...' }],
+ sections: ['prepare-executor'],
+ },
+ {
+ offset: 1004,
+ content: [{ text: 'Pulling docker image postgres:9.6.14 ...', style: 'term-fg-l-green' }],
+ sections: ['prepare-executor'],
+ },
+ ];
+
+ let result;
+
+ beforeEach(() => {
+ result = linesParser(mockData);
+ });
+
+ describe('regular line', () => {
+ it('adds a lineNumber property with correct index', () => {
+ expect(result[0].lineNumber).toEqual(0);
+ expect(result[1].line.lineNumber).toEqual(1);
+ });
+ });
+
+ describe('collpasible section', () => {
+ it('adds a `isClosed` property', () => {
+ expect(result[1].isClosed).toEqual(true);
+ });
+
+ it('adds a `isHeader` property', () => {
+ expect(result[1].isHeader).toEqual(true);
+ });
+
+ it('creates a lines array property with the content of the collpasible section', () => {
+ expect(result[1].lines.length).toEqual(2);
+ expect(result[1].lines[0].content).toEqual(mockData[2].content);
+ expect(result[1].lines[1].content).toEqual(mockData[3].content);
+ });
+ });
+});
diff --git a/spec/frontend/mocks/ce/lib/utils/axios_utils.js b/spec/frontend/mocks/ce/lib/utils/axios_utils.js
index b4065626b09..a3783b91f95 100644
--- a/spec/frontend/mocks/ce/lib/utils/axios_utils.js
+++ b/spec/frontend/mocks/ce/lib/utils/axios_utils.js
@@ -6,9 +6,10 @@ axios.isMock = true;
axios.defaults.adapter = config => {
const message =
`Unexpected unmocked request: ${JSON.stringify(config, null, 2)}\n` +
- 'Consider using the `axios-mock-adapter` in tests.';
+ 'Consider using the `axios-mock-adapter` module in tests.';
const error = new Error(message);
error.config = config;
+ global.fail(error);
throw error;
};
diff --git a/spec/frontend/mocks/mocks_helper_spec.js b/spec/frontend/mocks/mocks_helper_spec.js
index b8bb02c2f43..82e88b712c0 100644
--- a/spec/frontend/mocks/mocks_helper_spec.js
+++ b/spec/frontend/mocks/mocks_helper_spec.js
@@ -1,4 +1,4 @@
-/* eslint-disable global-require, promise/catch-or-return */
+/* eslint-disable global-require */
import path from 'path';
@@ -126,9 +126,8 @@ describe('mocks_helper.js', () => {
it('survives jest.isolateModules()', done => {
jest.isolateModules(() => {
const axios2 = require('~/lib/utils/axios_utils').default;
- expect(axios2.get('http://gitlab.com'))
- .rejects.toThrow('Unexpected unmocked request')
- .then(done);
+ expect(axios2.isMock).toBe(true);
+ done();
});
});
diff --git a/spec/frontend/mocks/node/jquery.js b/spec/frontend/mocks/node/jquery.js
index 34a25772f67..5c82f65406e 100644
--- a/spec/frontend/mocks/node/jquery.js
+++ b/spec/frontend/mocks/node/jquery.js
@@ -4,9 +4,11 @@ const $ = jest.requireActual('jquery');
// Fail tests for unmocked requests
$.ajax = () => {
- throw new Error(
+ const err = new Error(
'Unexpected unmocked jQuery.ajax() call! Make sure to mock jQuery.ajax() in tests.',
);
+ global.fail(err);
+ throw err;
};
// jquery is not an ES6 module
diff --git a/spec/frontend/mocks_spec.js b/spec/frontend/mocks_spec.js
index 2d2324120fd..a4a1fdea396 100644
--- a/spec/frontend/mocks_spec.js
+++ b/spec/frontend/mocks_spec.js
@@ -3,11 +3,22 @@ import axios from '~/lib/utils/axios_utils';
describe('Mock auto-injection', () => {
describe('mocks', () => {
- it('~/lib/utils/axios_utils', () =>
- expect(axios.get('http://gitlab.com')).rejects.toThrow('Unexpected unmocked request'));
+ let failMock;
+ beforeEach(() => {
+ failMock = jest.spyOn(global, 'fail').mockImplementation();
+ });
+
+ it('~/lib/utils/axios_utils', done => {
+ expect(axios.get('http://gitlab.com')).rejects.toThrow('Unexpected unmocked request');
+ setImmediate(() => {
+ expect(failMock).toHaveBeenCalledTimes(1);
+ done();
+ });
+ });
it('jQuery.ajax()', () => {
expect($.ajax).toThrow('Unexpected unmocked');
+ expect(failMock).toHaveBeenCalledTimes(1);
});
});
});
diff --git a/spec/graphql/features/authorization_spec.rb b/spec/graphql/features/authorization_spec.rb
index c427893f9cc..9a60ff3b78c 100644
--- a/spec/graphql/features/authorization_spec.rb
+++ b/spec/graphql/features/authorization_spec.rb
@@ -8,10 +8,10 @@ describe 'Gitlab::Graphql::Authorization' do
let(:permission_single) { :foo }
let(:permission_collection) { [:foo, :bar] }
let(:test_object) { double(name: 'My name') }
- let(:query_string) { '{ object() { name } }' }
+ let(:query_string) { '{ item() { name } }' }
let(:result) { execute_query(query_type)['data'] }
- subject { result['object'] }
+ subject { result['item'] }
shared_examples 'authorization with a single permission' do
it 'returns the protected field when user has permission' do
@@ -54,7 +54,7 @@ describe 'Gitlab::Graphql::Authorization' do
describe 'with a single permission' do
let(:query_type) do
query_factory do |query|
- query.field :object, type, null: true, resolve: ->(obj, args, ctx) { test_object }, authorize: permission_single
+ query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }, authorize: permission_single
end
end
@@ -65,7 +65,7 @@ describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
permissions = permission_collection
query_factory do |qt|
- qt.field :object, type, null: true, resolve: ->(obj, args, ctx) { test_object } do
+ qt.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object } do
authorize permissions
end
end
@@ -78,7 +78,7 @@ describe 'Gitlab::Graphql::Authorization' do
describe 'Field authorizations when field is a built in type' do
let(:query_type) do
query_factory do |query|
- query.field :object, type, null: true, resolve: ->(obj, args, ctx) { test_object }
+ query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }
end
end
@@ -131,7 +131,7 @@ describe 'Gitlab::Graphql::Authorization' do
describe 'Type authorizations' do
let(:query_type) do
query_factory do |query|
- query.field :object, type, null: true, resolve: ->(obj, args, ctx) { test_object }
+ query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }
end
end
@@ -168,7 +168,7 @@ describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
query_factory do |query|
- query.field :object, type, null: true, resolve: ->(obj, args, ctx) { test_object }, authorize: permission_2
+ query.field :item, type, null: true, resolve: ->(obj, args, ctx) { test_object }, authorize: permission_2
end
end
@@ -176,7 +176,7 @@ describe 'Gitlab::Graphql::Authorization' do
end
describe 'type authorizations when applied to a relay connection' do
- let(:query_string) { '{ object() { edges { node { name } } } }' }
+ let(:query_string) { '{ item() { edges { node { name } } } }' }
let(:second_test_object) { double(name: 'Second thing') }
let(:type) do
@@ -187,11 +187,11 @@ describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
query_factory do |query|
- query.field :object, type.connection_type, null: true, resolve: ->(obj, args, ctx) { [test_object, second_test_object] }
+ query.field :item, type.connection_type, null: true, resolve: ->(obj, args, ctx) { [test_object, second_test_object] }
end
end
- subject { result.dig('object', 'edges') }
+ subject { result.dig('item', 'edges') }
it 'returns only the elements visible to the user' do
permit(permission_single)
@@ -207,13 +207,13 @@ describe 'Gitlab::Graphql::Authorization' do
describe 'limiting connections with multiple objects' do
let(:query_type) do
query_factory do |query|
- query.field :object, type.connection_type, null: true, resolve: ->(obj, args, ctx) do
+ query.field :item, type.connection_type, null: true, resolve: ->(obj, args, ctx) do
[test_object, second_test_object]
end
end
end
- let(:query_string) { '{ object(first: 1) { edges { node { name } } } }' }
+ let(:query_string) { '{ item(first: 1) { edges { node { name } } } }' }
it 'only checks permissions for the first object' do
expect(Ability).to receive(:allowed?).with(user, permission_single, test_object) { true }
@@ -233,11 +233,11 @@ describe 'Gitlab::Graphql::Authorization' do
let(:query_type) do
query_factory do |query|
- query.field :object, [type], null: true, resolve: ->(obj, args, ctx) { [test_object] }
+ query.field :item, [type], null: true, resolve: ->(obj, args, ctx) { [test_object] }
end
end
- subject { result['object'].first }
+ subject { result['item'].first }
include_examples 'authorization with a single permission'
end
diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb
index dec6b23d72a..0a27bbecfef 100644
--- a/spec/graphql/gitlab_schema_spec.rb
+++ b/spec/graphql/gitlab_schema_spec.rb
@@ -129,7 +129,7 @@ describe GitlabSchema do
result = described_class.object_from_id(user.to_global_id.to_s)
- expect(result.__sync).to eq(user)
+ expect(result.sync).to eq(user)
end
it 'batchloads the queries' do
@@ -138,7 +138,7 @@ describe GitlabSchema do
expect do
[described_class.object_from_id(user1.to_global_id),
- described_class.object_from_id(user2.to_global_id)].map(&:__sync)
+ described_class.object_from_id(user2.to_global_id)].map(&:sync)
end.not_to exceed_query_limit(1)
end
end
@@ -149,7 +149,7 @@ describe GitlabSchema do
result = described_class.object_from_id(note.to_global_id)
- expect(result.__sync).to eq(note)
+ expect(result.sync).to eq(note)
end
it 'batchloads the queries' do
@@ -158,7 +158,7 @@ describe GitlabSchema do
expect do
[described_class.object_from_id(note1.to_global_id),
- described_class.object_from_id(note2.to_global_id)].map(&:__sync)
+ described_class.object_from_id(note2.to_global_id)].map(&:sync)
end.not_to exceed_query_limit(1)
end
end
diff --git a/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb b/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb
index 19f5a8907a2..aa0f5c55902 100644
--- a/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb
+++ b/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb
@@ -14,6 +14,6 @@ describe Mutations::ResolvesProject do
project = create(:project)
expect(Resolvers::ProjectResolver).to receive(:new).with(object: nil, context: context).and_call_original
- expect(mutation.resolve_project(full_path: project.full_path)).to eq(project)
+ expect(mutation.resolve_project(full_path: project.full_path).sync).to eq(project)
end
end
diff --git a/spec/graphql/resolvers/group_resolver_spec.rb b/spec/graphql/resolvers/group_resolver_spec.rb
index 5eb9cd06d15..7dec9ac1aa5 100644
--- a/spec/graphql/resolvers/group_resolver_spec.rb
+++ b/spec/graphql/resolvers/group_resolver_spec.rb
@@ -12,7 +12,7 @@ describe Resolvers::GroupResolver do
it 'batch-resolves groups by full path' do
paths = [group1.full_path, group2.full_path]
- result = batch(max_queries: 1) do
+ result = batch_sync(max_queries: 1) do
paths.map { |path| resolve_group(path) }
end
@@ -20,7 +20,7 @@ describe Resolvers::GroupResolver do
end
it 'resolves an unknown full_path to nil' do
- result = batch { resolve_group('unknown/project') }
+ result = batch_sync { resolve_group('unknown/project') }
expect(result).to be_nil
end
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 798fe00de97..d122c081069 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -110,7 +110,7 @@ describe Resolvers::IssuesResolver do
context "when passing a non existent, batch loaded project" do
let(:project) do
- BatchLoader.for("non-existent-path").batch do |_fake_paths, loader, _|
+ BatchLoader::GraphQL.for("non-existent-path").batch do |_fake_paths, loader, _|
loader.call("non-existent-path", nil)
end
end
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index ab3c426b2cd..97b8e5ed41c 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -17,7 +17,7 @@ describe Resolvers::MergeRequestsResolver do
describe '#resolve' do
it 'batch-resolves by target project full path and individual IID' do
- result = batch(max_queries: 2) do
+ result = batch_sync(max_queries: 2) do
resolve_mr(project, iid: iid_1) + resolve_mr(project, iid: iid_2)
end
@@ -25,7 +25,7 @@ describe Resolvers::MergeRequestsResolver do
end
it 'batch-resolves by target project full path and IIDS' do
- result = batch(max_queries: 2) do
+ result = batch_sync(max_queries: 2) do
resolve_mr(project, iids: [iid_1, iid_2])
end
@@ -33,7 +33,7 @@ describe Resolvers::MergeRequestsResolver do
end
it 'can batch-resolve merge requests from different projects' do
- result = batch(max_queries: 3) do
+ result = batch_sync(max_queries: 3) do
resolve_mr(project, iid: iid_1) +
resolve_mr(project, iid: iid_2) +
resolve_mr(other_project, iid: other_iid)
@@ -43,13 +43,13 @@ describe Resolvers::MergeRequestsResolver do
end
it 'resolves an unknown iid to be empty' do
- result = batch { resolve_mr(project, iid: -1) }
+ result = batch_sync { resolve_mr(project, iid: -1) }
- expect(result).to be_empty
+ expect(result.compact).to be_empty
end
it 'resolves empty iids to be empty' do
- result = batch { resolve_mr(project, iids: []) }
+ result = batch_sync { resolve_mr(project, iids: []) }
expect(result).to be_empty
end
diff --git a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
index 47591445fc0..639cc69650b 100644
--- a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
@@ -46,7 +46,7 @@ describe Resolvers::NamespaceProjectsResolver do
context "when passing a non existent, batch loaded namespace" do
let(:namespace) do
- BatchLoader.for("non-existent-path").batch do |_fake_paths, loader, _|
+ BatchLoader::GraphQL.for("non-existent-path").batch do |_fake_paths, loader, _|
loader.call("non-existent-path", nil)
end
end
diff --git a/spec/graphql/resolvers/project_resolver_spec.rb b/spec/graphql/resolvers/project_resolver_spec.rb
index 4fdbb3aa43e..d0fc2957909 100644
--- a/spec/graphql/resolvers/project_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_resolver_spec.rb
@@ -12,7 +12,7 @@ describe Resolvers::ProjectResolver do
it 'batch-resolves projects by full path' do
paths = [project1.full_path, project2.full_path]
- result = batch(max_queries: 1) do
+ result = batch_sync(max_queries: 1) do
paths.map { |path| resolve_project(path) }
end
@@ -20,7 +20,7 @@ describe Resolvers::ProjectResolver do
end
it 'resolves an unknown full_path to nil' do
- result = batch { resolve_project('unknown/project') }
+ result = batch_sync { resolve_project('unknown/project') }
expect(result).to be_nil
end
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index 6fbb6147d84..9330e75af11 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe AvatarsHelper do
include UploadHelpers
diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb
index f014537eb54..ad088398ce9 100644
--- a/spec/helpers/boards_helper_spec.rb
+++ b/spec/helpers/boards_helper_spec.rb
@@ -40,7 +40,7 @@ describe BoardsHelper do
assign(:project, project)
allow(helper).to receive(:current_user) { user }
- allow(helper).to receive(:can?).with(user, :admin_list, project).and_return(true)
+ allow(helper).to receive(:can?).with(user, :create_non_backlog_issues, board).and_return(true)
end
it 'returns a board_lists_path as lists_endpoint' do
diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb
index 824b3ab4fc1..9e53bc05a48 100644
--- a/spec/helpers/commits_helper_spec.rb
+++ b/spec/helpers/commits_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe CommitsHelper do
describe 'commit_author_link' do
diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb
index 18cf0031d5f..a70d8333f30 100644
--- a/spec/helpers/form_helper_spec.rb
+++ b/spec/helpers/form_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe FormHelper do
describe 'form_errors' do
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index f92b94a9583..950f951e22e 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -60,20 +60,19 @@ describe IconsHelper do
non_existing = 'non_existing_icon_sprite'
it 'raises in development mode' do
- allow(Rails.env).to receive(:development?).and_return(true)
+ stub_rails_env('development')
expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/)
end
it 'raises in test mode' do
- allow(Rails.env).to receive(:test?).and_return(true)
+ stub_rails_env('test')
expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/)
end
it 'does not raise in production mode' do
- allow(Rails.env).to receive(:test?).and_return(false)
- allow(Rails.env).to receive(:development?).and_return(false)
+ stub_rails_env('production')
expect { sprite_icon(non_existing) }.not_to raise_error
end
diff --git a/spec/helpers/import_helper_spec.rb b/spec/helpers/import_helper_spec.rb
index 6e8c13db9fe..8a1b1e859b1 100644
--- a/spec/helpers/import_helper_spec.rb
+++ b/spec/helpers/import_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe ImportHelper do
describe '#sanitize_project_name' do
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index bf50763d06f..3b08fc511a3 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe PageLayoutHelper do
describe 'page_description' do
diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb
index 8e336469c27..da2dc229c35 100644
--- a/spec/helpers/profiles_helper_spec.rb
+++ b/spec/helpers/profiles_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe ProfilesHelper do
describe '#commit_email_select_options' do
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index a6623bc7941..9165e91ddcd 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe UsersHelper do
include TermsHelper
diff --git a/spec/helpers/version_check_helper_spec.rb b/spec/helpers/version_check_helper_spec.rb
index e384e2bf9a0..edc0d64d031 100644
--- a/spec/helpers/version_check_helper_spec.rb
+++ b/spec/helpers/version_check_helper_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe VersionCheckHelper do
describe '#version_status_badge' do
it 'returns nil if not dev environment and not enabled' do
- allow(Rails.env).to receive(:production?) { false }
+ stub_rails_env('development')
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:version_check_enabled) { false }
expect(helper.version_status_badge).to be(nil)
@@ -11,7 +11,7 @@ describe VersionCheckHelper do
context 'when production and enabled' do
before do
- allow(Rails.env).to receive(:production?) { true }
+ stub_rails_env('production')
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:version_check_enabled) { true }
allow(VersionCheck).to receive(:url) { 'https://version.host.com/check.svg?gitlab_info=xxx' }
end
diff --git a/spec/javascripts/boards/issue_spec.js b/spec/javascripts/boards/issue_spec.js
index bb7abe52eae..05e6ea1394d 100644
--- a/spec/javascripts/boards/issue_spec.js
+++ b/spec/javascripts/boards/issue_spec.js
@@ -1,6 +1,6 @@
/* global ListIssue */
-import Vue from 'vue';
+import axios from '~/lib/utils/axios_utils';
import '~/boards/models/label';
import '~/boards/models/assignee';
import '~/boards/models/issue';
@@ -175,7 +175,7 @@ describe('Issue model', () => {
describe('update', () => {
it('passes assignee ids when there are assignees', done => {
- spyOn(Vue.http, 'patch').and.callFake((url, data) => {
+ spyOn(axios, 'patch').and.callFake((url, data) => {
expect(data.issue.assignee_ids).toEqual([1]);
done();
return Promise.resolve();
@@ -185,7 +185,7 @@ describe('Issue model', () => {
});
it('passes assignee ids of [0] when there are no assignees', done => {
- spyOn(Vue.http, 'patch').and.callFake((url, data) => {
+ spyOn(axios, 'patch').and.callFake((url, data) => {
expect(data.issue.assignee_ids).toEqual([0]);
done();
return Promise.resolve();
diff --git a/spec/javascripts/flash_spec.js b/spec/javascripts/flash_spec.js
index aecab331ead..bd8608b6bac 100644
--- a/spec/javascripts/flash_spec.js
+++ b/spec/javascripts/flash_spec.js
@@ -25,14 +25,6 @@ describe('Flash', () => {
'<script>alert("a");</script>',
);
});
-
- it('adds container classes when inside content wrapper', () => {
- el.innerHTML = createFlashEl('testing', 'alert', true);
-
- expect(el.querySelector('.flash-text').classList.contains('container-fluid')).toBeTruthy();
-
- expect(el.querySelector('.flash-text').classList.contains('container-limited')).toBeTruthy();
- });
});
describe('hideFlash', () => {
@@ -171,9 +163,7 @@ describe('Flash', () => {
it('adds container classes when inside content-wrapper', () => {
flash('test');
- expect(document.querySelector('.flash-text').className).toBe(
- 'flash-text container-fluid container-limited limit-container-width',
- );
+ expect(document.querySelector('.flash-text').className).toBe('flash-text');
});
it('does not add container when outside of content-wrapper', () => {
diff --git a/spec/javascripts/groups/components/app_spec.js b/spec/javascripts/groups/components/app_spec.js
index 31873311e16..23b2564d3f9 100644
--- a/spec/javascripts/groups/components/app_spec.js
+++ b/spec/javascripts/groups/components/app_spec.js
@@ -1,3 +1,4 @@
+import '~/flash';
import $ from 'jquery';
import Vue from 'vue';
@@ -333,7 +334,7 @@ describe('AppComponent', () => {
it('hides modal confirmation leave group and remove group item from tree', done => {
const notice = `You left the "${childGroupItem.fullName}" group.`;
- spyOn(vm.service, 'leaveGroup').and.returnValue(returnServicePromise({ notice }));
+ spyOn(vm.service, 'leaveGroup').and.returnValue(Promise.resolve({ data: { notice } }));
spyOn(vm.store, 'removeGroup').and.callThrough();
spyOn(window, 'Flash');
spyOn($, 'scrollTo');
diff --git a/spec/javascripts/groups/service/groups_service_spec.js b/spec/javascripts/groups/service/groups_service_spec.js
index 339e5131615..45db962a1ef 100644
--- a/spec/javascripts/groups/service/groups_service_spec.js
+++ b/spec/javascripts/groups/service/groups_service_spec.js
@@ -1,11 +1,8 @@
-import Vue from 'vue';
-import VueResource from 'vue-resource';
+import axios from '~/lib/utils/axios_utils';
import GroupsService from '~/groups/service/groups_service';
import { mockEndpoint, mockParentGroupItem } from '../mock_data';
-Vue.use(VueResource);
-
describe('GroupsService', () => {
let service;
@@ -15,8 +12,8 @@ describe('GroupsService', () => {
describe('getGroups', () => {
it('should return promise for `GET` request on provided endpoint', () => {
- spyOn(service.groups, 'get').and.stub();
- const queryParams = {
+ spyOn(axios, 'get').and.stub();
+ const params = {
page: 2,
filter: 'git',
sort: 'created_asc',
@@ -25,21 +22,21 @@ describe('GroupsService', () => {
service.getGroups(55, 2, 'git', 'created_asc', true);
- expect(service.groups.get).toHaveBeenCalledWith({ parent_id: 55 });
+ expect(axios.get).toHaveBeenCalledWith(mockEndpoint, { params: { parent_id: 55 } });
service.getGroups(null, 2, 'git', 'created_asc', true);
- expect(service.groups.get).toHaveBeenCalledWith(queryParams);
+ expect(axios.get).toHaveBeenCalledWith(mockEndpoint, { params });
});
});
describe('leaveGroup', () => {
it('should return promise for `DELETE` request on provided endpoint', () => {
- spyOn(Vue.http, 'delete').and.stub();
+ spyOn(axios, 'delete').and.stub();
service.leaveGroup(mockParentGroupItem.leavePath);
- expect(Vue.http.delete).toHaveBeenCalledWith(mockParentGroupItem.leavePath);
+ expect(axios.delete).toHaveBeenCalledWith(mockParentGroupItem.leavePath);
});
});
});
diff --git a/spec/javascripts/jobs/components/job_app_spec.js b/spec/javascripts/jobs/components/job_app_spec.js
index d3c1cf831bb..57ab1aa73f7 100644
--- a/spec/javascripts/jobs/components/job_app_spec.js
+++ b/spec/javascripts/jobs/components/job_app_spec.js
@@ -25,6 +25,7 @@ describe('Job App ', () => {
terminalPath: 'jobs/123/terminal',
pagePath: `${gl.TEST_HOST}jobs/123`,
projectPath: 'user-name/project-name',
+ subscriptionsMoreMinutesUrl: 'https://customers.gitlab.com/buy_pipeline_minutes',
logState:
'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D',
};
diff --git a/spec/javascripts/jobs/components/log/line_header_spec.js b/spec/javascripts/jobs/components/log/line_header_spec.js
new file mode 100644
index 00000000000..4efd412a6cd
--- /dev/null
+++ b/spec/javascripts/jobs/components/log/line_header_spec.js
@@ -0,0 +1,84 @@
+import { mount } from '@vue/test-utils';
+import LineHeader from '~/jobs/components/log/line_header.vue';
+import LineNumber from '~/jobs/components/log/line_number.vue';
+
+describe('Job Log Header Line', () => {
+ let wrapper;
+
+ const data = {
+ line: {
+ content: [
+ {
+ text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
+ style: 'term-fg-l-green',
+ },
+ ],
+ lineNumber: 0,
+ },
+ isClosed: true,
+ path: '/jashkenas/underscore/-/jobs/335',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(LineHeader, {
+ sync: false,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('line', () => {
+ beforeEach(() => {
+ createComponent(data);
+ });
+
+ it('renders the line number component', () => {
+ expect(wrapper.contains(LineNumber)).toBe(true);
+ });
+
+ it('renders a span the provided text', () => {
+ expect(wrapper.find('span').text()).toBe(data.line.content[0].text);
+ });
+
+ it('renders the provided style as a class attribute', () => {
+ expect(wrapper.find('span').classes()).toContain(data.line.content[0].style);
+ });
+ });
+
+ describe('when isCloses is true', () => {
+ beforeEach(() => {
+ createComponent({ ...data, isClosed: true });
+ });
+
+ it('sets icon name to be angle-right', () => {
+ expect(wrapper.vm.iconName).toEqual('angle-right');
+ });
+ });
+
+ describe('when isCloses is false', () => {
+ beforeEach(() => {
+ createComponent({ ...data, isClosed: false });
+ });
+
+ it('sets icon name to be angle-down', () => {
+ expect(wrapper.vm.iconName).toEqual('angle-down');
+ });
+ });
+
+ describe('on click', () => {
+ beforeEach(() => {
+ createComponent(data);
+ });
+
+ it('emits toggleLine event', () => {
+ wrapper.trigger('click');
+
+ expect(wrapper.emitted().toggleLine.length).toBe(1);
+ });
+ });
+});
diff --git a/spec/javascripts/jobs/components/log/line_number_spec.js b/spec/javascripts/jobs/components/log/line_number_spec.js
new file mode 100644
index 00000000000..fcf2edf9159
--- /dev/null
+++ b/spec/javascripts/jobs/components/log/line_number_spec.js
@@ -0,0 +1,40 @@
+import { shallowMount } from '@vue/test-utils';
+import LineNumber from '~/jobs/components/log/line_number.vue';
+
+describe('Job Log Line Number', () => {
+ let wrapper;
+
+ const data = {
+ lineNumber: 0,
+ path: '/jashkenas/underscore/-/jobs/335',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(LineNumber, {
+ sync: false,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent(data);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders incremented lineNunber by 1', () => {
+ expect(wrapper.text()).toBe('1');
+ });
+
+ it('renders link with lineNumber as an ID', () => {
+ expect(wrapper.attributes().id).toBe('L1');
+ });
+
+ it('links to the provided path with line number as anchor', () => {
+ expect(wrapper.attributes().href).toBe(`${data.path}#L1`);
+ });
+});
diff --git a/spec/javascripts/jobs/components/log/line_spec.js b/spec/javascripts/jobs/components/log/line_spec.js
new file mode 100644
index 00000000000..ea593e3c39a
--- /dev/null
+++ b/spec/javascripts/jobs/components/log/line_spec.js
@@ -0,0 +1,49 @@
+import { shallowMount } from '@vue/test-utils';
+import Line from '~/jobs/components/log/line.vue';
+import LineNumber from '~/jobs/components/log/line_number.vue';
+
+describe('Job Log Line', () => {
+ let wrapper;
+
+ const data = {
+ line: {
+ content: [
+ {
+ text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
+ style: 'term-fg-l-green',
+ },
+ ],
+ lineNumber: 0,
+ },
+ path: '/jashkenas/underscore/-/jobs/335',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(Line, {
+ sync: false,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent(data);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders the line number component', () => {
+ expect(wrapper.contains(LineNumber)).toBe(true);
+ });
+
+ it('renders a span the provided text', () => {
+ expect(wrapper.find('span').text()).toBe(data.line.content[0].text);
+ });
+
+ it('renders the provided style as a class attribute', () => {
+ expect(wrapper.find('span').classes()).toContain(data.line.content[0].style);
+ });
+});
diff --git a/spec/javascripts/monitoring/charts/area_spec.js b/spec/javascripts/monitoring/charts/area_spec.js
deleted file mode 100644
index 1e49a955815..00000000000
--- a/spec/javascripts/monitoring/charts/area_spec.js
+++ /dev/null
@@ -1,265 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { createStore } from '~/monitoring/stores';
-import { GlLink } from '@gitlab/ui';
-import { GlAreaChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
-import { shallowWrapperContainsSlotText } from 'spec/helpers/vue_test_utils_helper';
-import Area from '~/monitoring/components/charts/area.vue';
-import * as types from '~/monitoring/stores/mutation_types';
-import { TEST_HOST } from 'spec/test_constants';
-import MonitoringMock, { deploymentData } from '../mock_data';
-
-describe('Area component', () => {
- const mockSha = 'mockSha';
- const mockWidgets = 'mockWidgets';
- const mockSvgPathContent = 'mockSvgPathContent';
- const projectPath = `${TEST_HOST}/path/to/project`;
- const commitUrl = `${projectPath}/commit/${mockSha}`;
- let mockGraphData;
- let areaChart;
- let spriteSpy;
- let store;
-
- beforeEach(() => {
- store = createStore();
- store.commit(`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, MonitoringMock.data);
- store.commit(`monitoringDashboard/${types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS}`, deploymentData);
-
- [mockGraphData] = store.state.monitoringDashboard.groups[0].metrics;
-
- areaChart = shallowMount(Area, {
- propsData: {
- graphData: mockGraphData,
- containerWidth: 0,
- deploymentData: store.state.monitoringDashboard.deploymentData,
- projectPath,
- },
- slots: {
- default: mockWidgets,
- },
- store,
- });
-
- spriteSpy = spyOnDependency(Area, 'getSvgIconPathContent').and.callFake(
- () => new Promise(resolve => resolve(mockSvgPathContent)),
- );
- });
-
- afterEach(() => {
- areaChart.destroy();
- });
-
- it('renders chart title', () => {
- expect(areaChart.find({ ref: 'graphTitle' }).text()).toBe(mockGraphData.title);
- });
-
- it('contains graph widgets from slot', () => {
- expect(areaChart.find({ ref: 'graphWidgets' }).text()).toBe(mockWidgets);
- });
-
- describe('wrapped components', () => {
- describe('GitLab UI area chart', () => {
- let glAreaChart;
-
- beforeEach(() => {
- glAreaChart = areaChart.find(GlAreaChart);
- });
-
- it('is a Vue instance', () => {
- expect(glAreaChart.isVueInstance()).toBe(true);
- });
-
- it('receives data properties needed for proper chart render', () => {
- const props = glAreaChart.props();
-
- expect(props.data).toBe(areaChart.vm.chartData);
- expect(props.option).toBe(areaChart.vm.chartOptions);
- expect(props.formatTooltipText).toBe(areaChart.vm.formatTooltipText);
- expect(props.thresholds).toBe(areaChart.vm.thresholds);
- });
-
- it('recieves a tooltip title', () => {
- const mockTitle = 'mockTitle';
- areaChart.vm.tooltip.title = mockTitle;
-
- expect(shallowWrapperContainsSlotText(glAreaChart, 'tooltipTitle', mockTitle)).toBe(true);
- });
-
- describe('when tooltip is showing deployment data', () => {
- beforeEach(() => {
- areaChart.vm.tooltip.isDeployment = true;
- });
-
- it('uses deployment title', () => {
- expect(shallowWrapperContainsSlotText(glAreaChart, 'tooltipTitle', 'Deployed')).toBe(
- true,
- );
- });
-
- it('renders clickable commit sha in tooltip content', () => {
- areaChart.vm.tooltip.sha = mockSha;
- areaChart.vm.tooltip.commitUrl = commitUrl;
-
- const commitLink = areaChart.find(GlLink);
-
- expect(shallowWrapperContainsSlotText(commitLink, 'default', mockSha)).toBe(true);
- expect(commitLink.attributes('href')).toEqual(commitUrl);
- });
- });
- });
- });
-
- describe('methods', () => {
- describe('formatTooltipText', () => {
- const mockDate = deploymentData[0].created_at;
- const generateSeriesData = type => ({
- seriesData: [
- {
- seriesName: areaChart.vm.chartData[0].name,
- componentSubType: type,
- value: [mockDate, 5.55555],
- seriesIndex: 0,
- },
- ],
- value: mockDate,
- });
-
- describe('when series is of line type', () => {
- beforeEach(() => {
- areaChart.vm.formatTooltipText(generateSeriesData('line'));
- });
-
- it('formats tooltip title', () => {
- expect(areaChart.vm.tooltip.title).toBe('31 May 2017, 9:23PM');
- });
-
- it('formats tooltip content', () => {
- const name = 'Core Usage';
- const value = '5.556';
- const seriesLabel = areaChart.find(GlChartSeriesLabel);
-
- expect(seriesLabel.vm.color).toBe('');
- expect(shallowWrapperContainsSlotText(seriesLabel, 'default', name)).toBe(true);
- expect(areaChart.vm.tooltip.content).toEqual([{ name, value, color: undefined }]);
- expect(
- shallowWrapperContainsSlotText(areaChart.find(GlAreaChart), 'tooltipContent', value),
- ).toBe(true);
- });
- });
-
- describe('when series is of scatter type', () => {
- beforeEach(() => {
- areaChart.vm.formatTooltipText(generateSeriesData('scatter'));
- });
-
- it('formats tooltip title', () => {
- expect(areaChart.vm.tooltip.title).toBe('31 May 2017, 9:23PM');
- });
-
- it('formats tooltip sha', () => {
- expect(areaChart.vm.tooltip.sha).toBe('f5bcd1d9');
- });
- });
- });
-
- describe('setSvg', () => {
- const mockSvgName = 'mockSvgName';
-
- beforeEach(() => {
- areaChart.vm.setSvg(mockSvgName);
- });
-
- it('gets svg path content', () => {
- expect(spriteSpy).toHaveBeenCalledWith(mockSvgName);
- });
-
- it('sets svg path content', done => {
- areaChart.vm.$nextTick(() => {
- expect(areaChart.vm.svgs[mockSvgName]).toBe(`path://${mockSvgPathContent}`);
- done();
- });
- });
- });
-
- describe('onResize', () => {
- const mockWidth = 233;
-
- beforeEach(() => {
- spyOn(Element.prototype, 'getBoundingClientRect').and.callFake(() => ({
- width: mockWidth,
- }));
- areaChart.vm.onResize();
- });
-
- it('sets area chart width', () => {
- expect(areaChart.vm.width).toBe(mockWidth);
- });
- });
- });
-
- describe('computed', () => {
- describe('chartData', () => {
- let chartData;
- const seriesData = () => chartData[0];
-
- beforeEach(() => {
- ({ chartData } = areaChart.vm);
- });
-
- it('utilizes all data points', () => {
- expect(chartData.length).toBe(1);
- expect(seriesData().data.length).toBe(297);
- });
-
- it('creates valid data', () => {
- const { data } = seriesData();
-
- expect(
- data.filter(([time, value]) => new Date(time).getTime() > 0 && typeof value === 'number')
- .length,
- ).toBe(data.length);
- });
-
- it('formats line width correctly', () => {
- expect(chartData[0].lineStyle.width).toBe(2);
- });
- });
-
- describe('chartOptions', () => {
- describe('dataZoom', () => {
- it('contains an svg object within an array to properly render icon', () => {
- const dataZoomObject = [{}];
-
- expect(areaChart.vm.chartOptions.dataZoom).toEqual(dataZoomObject);
- });
- });
-
- describe('yAxis formatter', () => {
- let format;
-
- beforeEach(() => {
- format = areaChart.vm.chartOptions.yAxis.axisLabel.formatter;
- });
-
- it('rounds to 3 decimal places', () => {
- expect(format(0.88888)).toBe('0.889');
- });
- });
- });
-
- describe('scatterSeries', () => {
- it('utilizes deployment data', () => {
- expect(areaChart.vm.scatterSeries.data).toEqual([
- ['2017-05-31T21:23:37.881Z', 0],
- ['2017-05-30T20:08:04.629Z', 0],
- ['2017-05-30T17:42:38.409Z', 0],
- ]);
- });
- });
-
- describe('yAxisLabel', () => {
- it('constructs a label for the chart y-axis', () => {
- expect(areaChart.vm.yAxisLabel).toBe('CPU');
- });
- });
- });
-});
diff --git a/spec/javascripts/monitoring/components/dashboard_spec.js b/spec/javascripts/monitoring/components/dashboard_spec.js
index f3ec7520c6f..15e41e2fe93 100644
--- a/spec/javascripts/monitoring/components/dashboard_spec.js
+++ b/spec/javascripts/monitoring/components/dashboard_spec.js
@@ -378,7 +378,9 @@ describe('Dashboard', () => {
});
});
- describe('link to chart', () => {
+ // https://gitlab.com/gitlab-org/gitlab-ce/issues/66922
+ // eslint-disable-next-line jasmine/no-disabled-tests
+ xdescribe('link to chart', () => {
let wrapper;
const currentDashboard = 'TEST_DASHBOARD';
localVue.use(GlToast);
diff --git a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
index 807f1b8bbd3..8e955ec3b6b 100644
--- a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
+++ b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Banzai::Filter::BlockquoteFenceFilter do
include FilterSpecHelper
diff --git a/spec/lib/banzai/filter/front_matter_filter_spec.rb b/spec/lib/banzai/filter/front_matter_filter_spec.rb
index 90b383dbcff..1b5b1770615 100644
--- a/spec/lib/banzai/filter/front_matter_filter_spec.rb
+++ b/spec/lib/banzai/filter/front_matter_filter_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Banzai::Filter::FrontMatterFilter do
include FilterSpecHelper
diff --git a/spec/lib/banzai/pipeline/description_pipeline_spec.rb b/spec/lib/banzai/pipeline/description_pipeline_spec.rb
index d032ec71e45..5ecd3df5151 100644
--- a/spec/lib/banzai/pipeline/description_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/description_pipeline_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Banzai::Pipeline::DescriptionPipeline do
def parse(html)
diff --git a/spec/lib/banzai/pipeline/email_pipeline_spec.rb b/spec/lib/banzai/pipeline/email_pipeline_spec.rb
index eea25320f3d..77186861225 100644
--- a/spec/lib/banzai/pipeline/email_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/email_pipeline_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Banzai::Pipeline::EmailPipeline do
describe '.filters' do
diff --git a/spec/lib/banzai/pipeline/full_pipeline_spec.rb b/spec/lib/banzai/pipeline/full_pipeline_spec.rb
index 2b4d1b58676..f63b86d1451 100644
--- a/spec/lib/banzai/pipeline/full_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/full_pipeline_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Banzai::Pipeline::FullPipeline do
describe 'References' do
diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
index 3a9ecd2fb81..7eb63fea413 100644
--- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Banzai::Pipeline::GfmPipeline do
describe 'integration between parsing regular and external issue references' do
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index 015af20f220..4a485fbc2bd 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Banzai::Pipeline::WikiPipeline do
describe 'TableOfContents' do
diff --git a/spec/lib/gitlab/anonymous_session_spec.rb b/spec/lib/gitlab/anonymous_session_spec.rb
index 628aae81ada..94daa0f2470 100644
--- a/spec/lib/gitlab/anonymous_session_spec.rb
+++ b/spec/lib/gitlab/anonymous_session_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::AnonymousSession, :clean_gitlab_redis_shared_state do
let(:default_session_id) { '6919a6f1bb119dd7396fadc38fd18d0d' }
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 098c33f9cb1..0365d63ea9c 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -587,7 +587,8 @@ describe Gitlab::Auth do
:read_project,
:build_download_code,
:build_read_container_image,
- :build_create_container_image
+ :build_create_container_image,
+ :build_destroy_container_image
]
end
diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
index ad4fa4fe03a..c1f6871a568 100644
--- a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, :migration, schema: 20190315191339 do
let(:namespaces) { table(:namespaces) }
diff --git a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb b/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
index 740781f1aa5..fd35ddc49a2 100644
--- a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
+++ b/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::BackgroundMigration::ResetMergeStatus, :migration, schema: 20190528180441 do
let(:namespaces) { table(:namespaces) }
diff --git a/spec/lib/gitlab/checks/project_created_spec.rb b/spec/lib/gitlab/checks/project_created_spec.rb
index 14cb5e6ec66..373fef2a240 100644
--- a/spec/lib/gitlab/checks/project_created_spec.rb
+++ b/spec/lib/gitlab/checks/project_created_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::Checks::ProjectCreated, :clean_gitlab_redis_shared_state do
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb
index 3ca977aa48d..3de397760b4 100644
--- a/spec/lib/gitlab/checks/project_moved_spec.rb
+++ b/spec/lib/gitlab/checks/project_moved_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index cff4eb398bf..49f92f14559 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -1283,33 +1283,19 @@ describe Gitlab::Database::MigrationHelpers do
describe '#perform_background_migration_inline?' do
it 'returns true in a test environment' do
- allow(Rails.env)
- .to receive(:test?)
- .and_return(true)
+ stub_rails_env('test')
expect(model.perform_background_migration_inline?).to eq(true)
end
it 'returns true in a development environment' do
- allow(Rails.env)
- .to receive(:test?)
- .and_return(false)
-
- allow(Rails.env)
- .to receive(:development?)
- .and_return(true)
+ stub_rails_env('development')
expect(model.perform_background_migration_inline?).to eq(true)
end
it 'returns false in a production environment' do
- allow(Rails.env)
- .to receive(:test?)
- .and_return(false)
-
- allow(Rails.env)
- .to receive(:development?)
- .and_return(false)
+ stub_rails_env('production')
expect(model.perform_background_migration_inline?).to eq(false)
end
diff --git a/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb b/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb
index eed2a1b7b48..e6321d48e11 100644
--- a/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb
+++ b/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DatabaseImporters::CommonMetrics::Importer do
subject { described_class.new }
diff --git a/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb b/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb
index 94f544e59b3..e4e8a85e7bc 100644
--- a/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb
+++ b/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DatabaseImporters::CommonMetrics::PrometheusMetric do
it 'group enum equals ::PrometheusMetric' do
diff --git a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
index 3eb5db51224..6d61edaa870 100644
--- a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::CartfileLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
index 6bef6f57e64..cc1f09628ef 100644
--- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::ComposerJsonLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
index 6ecdb0d1247..c6b6dfa77cb 100644
--- a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::GemfileLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
index 256fe58925c..c1cbfa31684 100644
--- a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::GemspecLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
index f620d1b590c..9f8542a76c9 100644
--- a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::GodepsJsonLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
index 71e9381eaad..eb0c5e0675a 100644
--- a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::PackageJsonLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb b/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb
index 9bfb1b13a2b..5b69ef5af24 100644
--- a/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::Parser::Gemfile do
describe '#parse' do
diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
index eb81bc07760..77326e73505 100644
--- a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::PodfileLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
index 938726dd434..d522a08cdd9 100644
--- a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::PodspecJsonLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
index 540eb2fadfe..baabd0c0460 100644
--- a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::PodspecLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
index 957a87985a2..04ac5f10479 100644
--- a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker::RequirementsTxtLinker do
describe '.support?' do
diff --git a/spec/lib/gitlab/dependency_linker_spec.rb b/spec/lib/gitlab/dependency_linker_spec.rb
index 98e46d62ca0..3ea3334caf0 100644
--- a/spec/lib/gitlab/dependency_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::DependencyLinker do
describe '.link' do
diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb
index dce56bbd2c4..d221f39c2ed 100644
--- a/spec/lib/gitlab/favicon_spec.rb
+++ b/spec/lib/gitlab/favicon_spec.rb
@@ -1,14 +1,14 @@
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe Gitlab::Favicon, :request_store do
describe '.main' do
it 'defaults to favicon.png' do
- allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production'))
+ stub_rails_env('production')
expect(described_class.main).to match_asset_path '/assets/favicon.png'
end
it 'has blue favicon for development', unless: Gitlab.ee? do
- allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development'))
+ stub_rails_env('development')
expect(described_class.main).to match_asset_path '/assets/favicon-blue.png'
end
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::Favicon, :request_store do
context 'asset host' do
before do
- allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production'))
+ stub_rails_env('production')
end
it 'returns a relative url when the asset host is not configured' do
diff --git a/spec/lib/gitlab/file_markdown_link_builder_spec.rb b/spec/lib/gitlab/file_markdown_link_builder_spec.rb
index feb2776c5d0..d9e2e162ae8 100644
--- a/spec/lib/gitlab/file_markdown_link_builder_spec.rb
+++ b/spec/lib/gitlab/file_markdown_link_builder_spec.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::FileMarkdownLinkBuilder do
let(:custom_class) do
diff --git a/spec/lib/gitlab/file_type_detection_spec.rb b/spec/lib/gitlab/file_type_detection_spec.rb
index 5e9b8988cc8..22ec7d414e8 100644
--- a/spec/lib/gitlab/file_type_detection_spec.rb
+++ b/spec/lib/gitlab/file_type_detection_spec.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::FileTypeDetection do
def upload_fixture(filename)
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index 81658874be7..be6ab0c1200 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -74,6 +74,11 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
end
end
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
+
context 'when limiting is disabled' do
let(:limits) { false }
@@ -100,6 +105,11 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
expect(subject.size).to eq(3)
end
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
end
end
@@ -120,6 +130,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('0+') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq 1000 }
+ end
+
it { expect(subject.size).to eq(0) }
context 'when limiting is disabled' do
@@ -139,6 +155,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('3') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
+
it { expect(subject.size).to eq(3) }
end
end
@@ -164,6 +186,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('10+') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq 10 }
+ end
+
it { expect(subject.size).to eq(10) }
context 'when limiting is disabled' do
@@ -183,6 +211,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('11') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
+
it { expect(subject.size).to eq(11) }
end
end
@@ -204,6 +238,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('3+') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq 120 }
+ end
+
it { expect(subject.size).to eq(3) }
context 'when limiting is disabled' do
@@ -223,6 +263,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('11') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
+
it { expect(subject.size).to eq(11) }
end
end
@@ -248,6 +294,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('10') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
+
it { expect(subject.size).to eq(10) }
end
end
@@ -270,6 +322,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('9+') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
+
it { expect(subject.size).to eq(9) }
context 'when limiting is disabled' do
@@ -289,6 +347,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('10') }
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq file_count * line_count }
+ end
+
it { expect(subject.size).to eq(10) }
end
end
@@ -316,6 +380,11 @@ describe Gitlab::Git::DiffCollection, :seed_helper do
subject { super().real_size }
it { is_expected.to eq('0')}
end
+
+ describe '#line_count' do
+ subject { super().line_count }
+ it { is_expected.to eq 0 }
+ end
end
describe '#each' do
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 99d563e03ec..1c5f72a4396 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -265,7 +265,7 @@ describe Gitlab::GitalyClient do
context 'in production and when RequestStore is enabled', :request_store do
before do
- allow(Rails.env).to receive(:production?).and_return(true)
+ stub_rails_env('production')
end
context 'when the maximum number of calls is enforced by a feature flag' do
diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb
index 47e6f5d4220..a3d7e42733d 100644
--- a/spec/lib/gitlab/gpg/commit_spec.rb
+++ b/spec/lib/gitlab/gpg/commit_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::Gpg::Commit do
describe '#signature' do
diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
index 1a2c6ef25c4..1dfca0b056c 100644
--- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
+++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do
describe '#run' do
diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb
index 48bbd7f854c..77d318c9b23 100644
--- a/spec/lib/gitlab/gpg_spec.rb
+++ b/spec/lib/gitlab/gpg_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::Gpg do
describe '.fingerprints_from_key' do
diff --git a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
index 7a7ae373058..aada9285b31 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
@@ -32,7 +32,8 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
let(:presented_type) { double('parent type', object: presented_object) }
let(:query_type) { GraphQL::ObjectType.new }
let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
- let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: { current_user: current_user }, object: nil) }
+ let(:query_context) { OpenStruct.new(schema: schema) }
+ let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema, context: query_context), values: { current_user: current_user }, object: nil) }
subject(:resolved) { service.authorized_resolve.call(presented_type, {}, context) }
context 'scalar types' do
diff --git a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
index 50138d272c4..23762666ba8 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
@@ -46,9 +46,9 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
end
- describe '#authorized?' do
+ describe '#authorized_resource?' do
it 'is true' do
- expect(loading_resource.authorized?(project)).to be(true)
+ expect(loading_resource.authorized_resource?(project)).to be(true)
end
end
end
@@ -72,9 +72,9 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
end
- describe '#authorized?' do
+ describe '#authorized_resource?' do
it 'is false' do
- expect(loading_resource.authorized?(project)).to be(false)
+ expect(loading_resource.authorized_resource?(project)).to be(false)
end
end
end
@@ -121,9 +121,9 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
end
- describe '#authorized?' do
+ describe '#authorized_resource?' do
it 'raises a comprehensive error message' do
- expect { loading_resource.authorized?(project) }.to raise_error(error)
+ expect { loading_resource.authorized_resource?(project) }.to raise_error(error)
end
end
end
diff --git a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb
index fefa2881b18..4eb121794e1 100644
--- a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb
+++ b/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::Graphql::Connections::KeysetConnection do
end
def encoded_property(value)
- Base64.strict_encode64(value.to_s)
+ Base64Bp.urlsafe_encode64(value.to_s, padding: false)
end
describe '#cursor_from_nodes' do
diff --git a/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb
index 46dd1777285..22d8aa4274a 100644
--- a/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb
+++ b/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb
@@ -12,7 +12,7 @@ describe Gitlab::Graphql::Loaders::BatchLfsOidLoader do
it 'batch-resolves LFS blob IDs' do
expect(Gitlab::Git::Blob).to receive(:batch_lfs_pointers).once.and_call_original
- result = batch do
+ result = batch_sync do
[blob, otherblob].map { |b| described_class.new(repository, b.id).find }
end
diff --git a/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb
index 4609593ef6a..a4bbd868558 100644
--- a/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb
+++ b/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb
@@ -9,8 +9,8 @@ describe Gitlab::Graphql::Loaders::BatchModelLoader do
issue_result = described_class.new(Issue, issue.id).find
user_result = described_class.new(User, user.id).find
- expect(issue_result.__sync).to eq(issue)
- expect(user_result.__sync).to eq(user)
+ expect(issue_result.sync).to eq(issue)
+ expect(user_result.sync).to eq(user)
end
it 'only queries once per model' do
@@ -21,7 +21,7 @@ describe Gitlab::Graphql::Loaders::BatchModelLoader do
expect do
[described_class.new(User, other_user.id).find,
described_class.new(User, user.id).find,
- described_class.new(Issue, issue.id).find].map(&:__sync)
+ described_class.new(Issue, issue.id).find].map(&:sync)
end.not_to exceed_query_limit(2)
end
end
diff --git a/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb
index 927476cc655..136027736c3 100644
--- a/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb
+++ b/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::Graphql::Loaders::PipelineForShaLoader do
pipeline2 = create(:ci_pipeline, project: project, ref: project.default_branch, sha: project.commit.sha)
pipeline3 = create(:ci_pipeline, project: project, ref: 'improve/awesome', sha: project.commit('improve/awesome').sha)
- result = batch(max_queries: 1) do
+ result = batch_sync(max_queries: 1) do
[pipeline1.sha, pipeline3.sha].map { |sha| described_class.new(project, sha).find_last }
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index ec4a6ef05b9..47ba7eff8ed 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -26,6 +26,7 @@ issues:
events:
- author
- project
+- group
- target
- push_event_payload
notes:
@@ -62,6 +63,8 @@ milestone:
- participants
- events
- boards
+- milestone_release
+- release
snippets:
- author
- project
@@ -72,6 +75,8 @@ releases:
- author
- project
- links
+- milestone_release
+- milestone
links:
- release
project_members:
@@ -484,3 +489,6 @@ lists:
- board
- label
- list_user_preferences
+milestone_releases:
+- milestone
+- release
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index f0545176a90..516e62c4728 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -33,6 +33,7 @@ Event:
- target_type
- target_id
- project_id
+- group_id
- created_at
- updated_at
- action
diff --git a/spec/lib/gitlab/jwt_authenticatable_spec.rb b/spec/lib/gitlab/jwt_authenticatable_spec.rb
new file mode 100644
index 00000000000..0c1c491b308
--- /dev/null
+++ b/spec/lib/gitlab/jwt_authenticatable_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::JwtAuthenticatable do
+ let(:test_class) do
+ Class.new do
+ include Gitlab::JwtAuthenticatable
+
+ def self.secret_path
+ Rails.root.join('tmp', 'tests', '.jwt_shared_secret')
+ end
+ end
+ end
+
+ before do
+ begin
+ File.delete(test_class.secret_path)
+ rescue Errno::ENOENT
+ end
+
+ test_class.write_secret
+ end
+
+ describe '.secret' do
+ subject(:secret) { test_class.secret }
+
+ it 'returns 32 bytes' do
+ expect(secret).to be_a(String)
+ expect(secret.length).to eq(32)
+ expect(secret.encoding).to eq(Encoding::ASCII_8BIT)
+ end
+
+ it 'accepts a trailing newline' do
+ File.open(test_class.secret_path, 'a') { |f| f.write "\n" }
+
+ expect(secret.length).to eq(32)
+ end
+
+ it 'raises an exception if the secret file cannot be read' do
+ File.delete(test_class.secret_path)
+
+ expect { secret }.to raise_exception(Errno::ENOENT)
+ end
+
+ it 'raises an exception if the secret file contains the wrong number of bytes' do
+ File.truncate(test_class.secret_path, 0)
+
+ expect { secret }.to raise_exception(RuntimeError)
+ end
+ end
+
+ describe '.write_secret' do
+ it 'uses mode 0600' do
+ expect(File.stat(test_class.secret_path).mode & 0777).to eq(0600)
+ end
+
+ it 'writes base64 data' do
+ bytes = Base64.strict_decode64(File.read(test_class.secret_path))
+
+ expect(bytes).not_to be_empty
+ end
+ end
+
+ describe '.decode_jwt_for_issuer' do
+ let(:payload) { { 'iss' => 'test_issuer' } }
+
+ it 'accepts a correct header' do
+ encoded_message = JWT.encode(payload, test_class.secret, 'HS256')
+
+ expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.not_to raise_error
+ end
+
+ it 'raises an error when the JWT is not signed' do
+ encoded_message = JWT.encode(payload, nil, 'none')
+
+ expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.to raise_error(JWT::DecodeError)
+ end
+
+ it 'raises an error when the header is signed with the wrong secret' do
+ encoded_message = JWT.encode(payload, 'wrongsecret', 'HS256')
+
+ expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.to raise_error(JWT::DecodeError)
+ end
+
+ it 'raises an error when the issuer is incorrect' do
+ payload['iss'] = 'somebody else'
+ encoded_message = JWT.encode(payload, test_class.secret, 'HS256')
+
+ expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.to raise_error(JWT::DecodeError)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
index 7395b095454..f7f510f01db 100644
--- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::Kubernetes::Helm::InstallCommand do
let(:files) { { 'ca.pem': 'some file content' } }
diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
index fce2aded786..64cadcc011c 100644
--- a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::Kubernetes::Helm::Pod do
describe '#generate' do
diff --git a/spec/lib/gitlab/prometheus/metric_group_spec.rb b/spec/lib/gitlab/prometheus/metric_group_spec.rb
index a45dd0af91e..787f14daf47 100644
--- a/spec/lib/gitlab/prometheus/metric_group_spec.rb
+++ b/spec/lib/gitlab/prometheus/metric_group_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::Prometheus::MetricGroup do
describe '.common_metrics' do
diff --git a/spec/lib/gitlab/query_limiting/transaction_spec.rb b/spec/lib/gitlab/query_limiting/transaction_spec.rb
index 39d5a575efc..4e906314b5a 100644
--- a/spec/lib/gitlab/query_limiting/transaction_spec.rb
+++ b/spec/lib/gitlab/query_limiting/transaction_spec.rb
@@ -86,9 +86,7 @@ describe Gitlab::QueryLimiting::Transaction do
it 'returns false in a production environment' do
transaction = described_class.new
- expect(Rails.env)
- .to receive(:test?)
- .and_return(false)
+ stub_rails_env('production')
expect(transaction.raise_error?).to eq(false)
end
diff --git a/spec/lib/gitlab/query_limiting_spec.rb b/spec/lib/gitlab/query_limiting_spec.rb
index f0d0340cd6e..e9c6bbc35a3 100644
--- a/spec/lib/gitlab/query_limiting_spec.rb
+++ b/spec/lib/gitlab/query_limiting_spec.rb
@@ -9,14 +9,14 @@ describe Gitlab::QueryLimiting do
end
it 'returns true in a development environment' do
- allow(Rails.env).to receive(:development?).and_return(true)
+ stub_rails_env('development')
+ stub_rails_env('development')
expect(described_class.enable?).to eq(true)
end
it 'returns false on GitLab.com' do
- expect(Rails.env).to receive(:development?).and_return(false)
- expect(Rails.env).to receive(:test?).and_return(false)
+ stub_rails_env('production')
allow(Gitlab).to receive(:com?).and_return(true)
expect(described_class.enable?).to eq(false)
@@ -24,8 +24,7 @@ describe Gitlab::QueryLimiting do
it 'returns false in a non GitLab.com' do
allow(Gitlab).to receive(:com?).and_return(false)
- expect(Rails.env).to receive(:development?).and_return(false)
- expect(Rails.env).to receive(:test?).and_return(false)
+ stub_rails_env('production')
expect(described_class.enable?).to eq(false)
end
diff --git a/spec/lib/gitlab/sidekiq_config_spec.rb b/spec/lib/gitlab/sidekiq_config_spec.rb
index 1e8ccb447b1..49efbac160a 100644
--- a/spec/lib/gitlab/sidekiq_config_spec.rb
+++ b/spec/lib/gitlab/sidekiq_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Gitlab::SidekiqConfig do
describe '.workers' do
diff --git a/spec/lib/gitlab/tracing_spec.rb b/spec/lib/gitlab/tracing_spec.rb
index db75ce2a998..e913bb600ec 100644
--- a/spec/lib/gitlab/tracing_spec.rb
+++ b/spec/lib/gitlab/tracing_spec.rb
@@ -59,7 +59,7 @@ describe Gitlab::Tracing do
it 'returns the correct state for .tracing_url' do
expect(described_class).to receive(:tracing_url_enabled?).and_return(tracing_url_enabled?)
allow(described_class).to receive(:tracing_url_template).and_return(tracing_url_template)
- allow(Gitlab::CorrelationId).to receive(:current_id).and_return(correlation_id)
+ allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return(correlation_id)
allow(Gitlab).to receive(:process_name).and_return(process_name)
expect(described_class.tracing_url).to eq(tracing_url)
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index df8a1f82f81..6d1d7e48326 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -4,80 +4,114 @@
require 'spec_helper'
describe Gitlab::UrlBlocker do
+ include StubRequests
+
describe '#validate!' do
+ subject { described_class.validate!(import_url) }
+
+ shared_examples 'validates URI and hostname' do
+ it 'runs the url validations' do
+ uri, hostname = subject
+
+ expect(uri).to eq(Addressable::URI.parse(expected_uri))
+ expect(hostname).to eq(expected_hostname)
+ end
+ end
+
context 'when URI is nil' do
let(:import_url) { nil }
- it 'returns no URI and hostname' do
- uri, hostname = described_class.validate!(import_url)
-
- expect(uri).to be(nil)
- expect(hostname).to be(nil)
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { nil }
+ let(:expected_hostname) { nil }
end
end
context 'when URI is internal' do
let(:import_url) { 'http://localhost' }
- it 'returns URI and no hostname' do
- uri, hostname = described_class.validate!(import_url)
-
- expect(uri).to eq(Addressable::URI.parse('http://[::1]'))
- expect(hostname).to eq('localhost')
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://[::1]' }
+ let(:expected_hostname) { 'localhost' }
end
end
context 'when the URL hostname is a domain' do
- let(:import_url) { 'https://example.org' }
+ context 'when domain can be resolved' do
+ let(:import_url) { 'https://example.org' }
- it 'returns URI and hostname' do
- uri, hostname = described_class.validate!(import_url)
+ before do
+ stub_dns(import_url, ip_address: '93.184.216.34')
+ end
- expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34'))
- expect(hostname).to eq('example.org')
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'https://93.184.216.34' }
+ let(:expected_hostname) { 'example.org' }
+ end
+ end
+
+ context 'when domain cannot be resolved' do
+ let(:import_url) { 'http://foobar.x' }
+
+ it 'raises an error' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
end
end
context 'when the URL hostname is an IP address' do
let(:import_url) { 'https://93.184.216.34' }
- it 'returns URI and no hostname' do
- uri, hostname = described_class.validate!(import_url)
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ end
+
+ context 'when the address is invalid' do
+ let(:import_url) { 'http://1.1.1.1.1' }
- expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34'))
- expect(hostname).to be(nil)
+ it 'raises an error' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
end
end
context 'disabled DNS rebinding protection' do
+ subject { described_class.validate!(import_url, dns_rebind_protection: false) }
+
context 'when URI is internal' do
let(:import_url) { 'http://localhost' }
- it 'returns URI and no hostname' do
- uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false)
-
- expect(uri).to eq(Addressable::URI.parse('http://localhost'))
- expect(hostname).to be(nil)
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
end
end
context 'when the URL hostname is a domain' do
let(:import_url) { 'https://example.org' }
- it 'returns URI and no hostname' do
- uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false)
+ before do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+ end
- expect(uri).to eq(Addressable::URI.parse('https://example.org'))
- expect(hostname).to eq(nil)
+ context 'when domain can be resolved' do
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ end
end
- context 'when it cannot be resolved' do
+ context 'when domain cannot be resolved' do
let(:import_url) { 'http://foobar.x' }
- it 'raises error' do
- stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
-
- expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError)
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
end
end
end
@@ -85,20 +119,17 @@ describe Gitlab::UrlBlocker do
context 'when the URL hostname is an IP address' do
let(:import_url) { 'https://93.184.216.34' }
- it 'returns URI and no hostname' do
- uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false)
-
- expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34'))
- expect(hostname).to be(nil)
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
end
context 'when it is invalid' do
let(:import_url) { 'http://1.1.1.1.1' }
- it 'raises an error' do
- stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
-
- expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError)
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
end
end
end
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 98421cd12d3..88bc5034da5 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -200,57 +200,6 @@ describe Gitlab::Workhorse do
end
end
- describe ".secret" do
- subject { described_class.secret }
-
- before do
- described_class.instance_variable_set(:@secret, nil)
- described_class.write_secret
- end
-
- it 'returns 32 bytes' do
- expect(subject).to be_a(String)
- expect(subject.length).to eq(32)
- expect(subject.encoding).to eq(Encoding::ASCII_8BIT)
- end
-
- it 'accepts a trailing newline' do
- File.open(described_class.secret_path, 'a') { |f| f.write "\n" }
- expect(subject.length).to eq(32)
- end
-
- it 'raises an exception if the secret file cannot be read' do
- File.delete(described_class.secret_path)
- expect { subject }.to raise_exception(Errno::ENOENT)
- end
-
- it 'raises an exception if the secret file contains the wrong number of bytes' do
- File.truncate(described_class.secret_path, 0)
- expect { subject }.to raise_exception(RuntimeError)
- end
- end
-
- describe ".write_secret" do
- let(:secret_path) { described_class.secret_path }
- before do
- begin
- File.delete(secret_path)
- rescue Errno::ENOENT
- end
-
- described_class.write_secret
- end
-
- it 'uses mode 0600' do
- expect(File.stat(secret_path).mode & 0777).to eq(0600)
- end
-
- it 'writes base64 data' do
- bytes = Base64.strict_decode64(File.read(secret_path))
- expect(bytes).not_to be_empty
- end
- end
-
describe '#verify_api_request!' do
let(:header_key) { described_class::INTERNAL_API_REQUEST_HEADER }
let(:payload) { { 'iss' => 'gitlab-workhorse' } }
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index 1fc363460ae..589dac61528 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
-
-require_dependency 'gitlab'
+require 'spec_helper'
describe Gitlab do
describe '.root' do
@@ -113,7 +111,7 @@ describe Gitlab do
it 'is true when dev env' do
allow(described_class).to receive_messages(com?: false, org?: false)
- allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development'))
+ stub_rails_env('development')
expect(described_class.dev_env_org_or_com?).to eq true
end
diff --git a/spec/mailers/abuse_report_mailer_spec.rb b/spec/mailers/abuse_report_mailer_spec.rb
index f96870cc112..86153071cd3 100644
--- a/spec/mailers/abuse_report_mailer_spec.rb
+++ b/spec/mailers/abuse_report_mailer_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe AbuseReportMailer do
include EmailSpec::Matchers
diff --git a/spec/mailers/email_rejection_mailer_spec.rb b/spec/mailers/email_rejection_mailer_spec.rb
index bbe0a50ae8e..2ce2e3e1410 100644
--- a/spec/mailers/email_rejection_mailer_spec.rb
+++ b/spec/mailers/email_rejection_mailer_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe EmailRejectionMailer do
include EmailSpec::Matchers
diff --git a/spec/mailers/repository_check_mailer_spec.rb b/spec/mailers/repository_check_mailer_spec.rb
index 3dce89f5be2..757d3dfa797 100644
--- a/spec/mailers/repository_check_mailer_spec.rb
+++ b/spec/mailers/repository_check_mailer_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe RepositoryCheckMailer do
include EmailSpec::Matchers
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index a5f8e999d5d..814df472389 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe AbuseReport do
set(:report) { create(:abuse_report) }
diff --git a/spec/models/active_session_spec.rb b/spec/models/active_session_spec.rb
index 2a689754ee0..b1f93dc7189 100644
--- a/spec/models/active_session_spec.rb
+++ b/spec/models/active_session_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe ActiveSession, :clean_gitlab_redis_shared_state do
let(:user) do
diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb
index 209d138f956..2c32028c3e5 100644
--- a/spec/models/appearance_spec.rb
+++ b/spec/models/appearance_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Appearance do
subject { build(:appearance) }
diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb
index 8364293b908..62a75bde63b 100644
--- a/spec/models/blob_spec.rb
+++ b/spec/models/blob_spec.rb
@@ -1,7 +1,7 @@
# encoding: utf-8
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Blob do
include FakeBlobHelpers
diff --git a/spec/models/board_spec.rb b/spec/models/board_spec.rb
index 54452faa0e1..f6eee67e539 100644
--- a/spec/models/board_spec.rb
+++ b/spec/models/board_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Board do
describe 'relationships' do
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 7d84d094bdf..63ca383ac4b 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -323,6 +323,25 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#merge_train_pipeline?' do
+ subject { pipeline.merge_train_pipeline? }
+
+ let!(:pipeline) do
+ create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: ref, target_sha: 'xxx')
+ end
+
+ let(:merge_request) { create(:merge_request) }
+ let(:ref) { 'refs/merge-requests/1/train' }
+
+ it { is_expected.to be_truthy }
+
+ context 'when ref is merge ref' do
+ let(:ref) { 'refs/merge-requests/1/merge' }
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
describe '#merge_request_ref?' do
subject { pipeline.merge_request_ref? }
@@ -333,6 +352,48 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#merge_train_ref?' do
+ subject { pipeline.merge_train_ref? }
+
+ it 'calls Mergetrain#merge_train_ref?' do
+ expect(MergeRequest).to receive(:merge_train_ref?).with(pipeline.ref)
+
+ subject
+ end
+ end
+
+ describe '#merge_request_event_type' do
+ subject { pipeline.merge_request_event_type }
+
+ before do
+ allow(pipeline).to receive(:merge_request_event?) { true }
+ end
+
+ context 'when pipeline is merge train pipeline' do
+ before do
+ allow(pipeline).to receive(:merge_train_pipeline?) { true }
+ end
+
+ it { is_expected.to eq(:merge_train) }
+ end
+
+ context 'when pipeline is merge request pipeline' do
+ before do
+ allow(pipeline).to receive(:merge_request_pipeline?) { true }
+ end
+
+ it { is_expected.to eq(:merged_result) }
+ end
+
+ context 'when pipeline is detached merge request pipeline' do
+ before do
+ allow(pipeline).to receive(:detached_merge_request_pipeline?) { true }
+ end
+
+ it { is_expected.to eq(:detached) }
+ end
+ end
+
describe '#legacy_detached_merge_request_pipeline?' do
subject { pipeline.legacy_detached_merge_request_pipeline? }
@@ -782,7 +843,8 @@ describe Ci::Pipeline, :mailer do
'CI_MERGE_REQUEST_TITLE' => merge_request.title,
'CI_MERGE_REQUEST_ASSIGNEES' => merge_request.assignee_username_list,
'CI_MERGE_REQUEST_MILESTONE' => milestone.title,
- 'CI_MERGE_REQUEST_LABELS' => labels.map(&:title).join(','))
+ 'CI_MERGE_REQUEST_LABELS' => labels.map(&:title).join(','),
+ 'CI_MERGE_REQUEST_EVENT_TYPE' => pipeline.merge_request_event_type.to_s)
end
context 'when source project does not exist' do
diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb
index f6d5d05e4a0..bddc09decc3 100644
--- a/spec/models/clusters/applications/cert_manager_spec.rb
+++ b/spec/models/clusters/applications/cert_manager_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Clusters::Applications::CertManager do
let(:cert_manager) { create(:clusters_applications_cert_manager) }
diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb
index 00b5c72a3d3..9672129bb1e 100644
--- a/spec/models/clusters/applications/helm_spec.rb
+++ b/spec/models/clusters/applications/helm_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Clusters::Applications::Helm do
include_examples 'cluster application core specs', :clusters_applications_helm
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index 057517d3820..f984f6ba0ce 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Clusters::Applications::Ingress do
let(:ingress) { create(:clusters_applications_ingress) }
diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb
index 3ff66a074e4..1b39328752d 100644
--- a/spec/models/clusters/applications/jupyter_spec.rb
+++ b/spec/models/clusters/applications/jupyter_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Clusters::Applications::Jupyter do
include_examples 'cluster application core specs', :clusters_applications_jupyter
diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb
index 334f10526cb..3825994b733 100644
--- a/spec/models/clusters/applications/knative_spec.rb
+++ b/spec/models/clusters/applications/knative_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Clusters::Applications::Knative do
let(:knative) { create(:clusters_applications_knative) }
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index eb6ccba5584..8fc3b7e4c40 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Clusters::Applications::Prometheus do
include KubernetesHelpers
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index 4abe45a2152..b420a180524 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Clusters::Applications::Runner do
let(:ci_runner) { create(:ci_runner) }
diff --git a/spec/models/concerns/blocks_json_serialization_spec.rb b/spec/models/concerns/blocks_json_serialization_spec.rb
index e8657c45a93..0ef5be3cb61 100644
--- a/spec/models/concerns/blocks_json_serialization_spec.rb
+++ b/spec/models/concerns/blocks_json_serialization_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe BlocksJsonSerialization do
DummyModel = Class.new do
diff --git a/spec/models/concerns/cacheable_attributes_spec.rb b/spec/models/concerns/cacheable_attributes_spec.rb
index da46effe411..d8f940a808e 100644
--- a/spec/models/concerns/cacheable_attributes_spec.rb
+++ b/spec/models/concerns/cacheable_attributes_spec.rb
@@ -131,7 +131,7 @@ describe CacheableAttributes do
context 'in production environment' do
before do
- expect(Rails.env).to receive(:production?).and_return(true)
+ stub_rails_env('production')
end
it 'returns an uncached record and logs a warning' do
@@ -143,7 +143,7 @@ describe CacheableAttributes do
context 'in other environments' do
before do
- expect(Rails.env).to receive(:production?).and_return(false)
+ stub_rails_env('development')
end
it 'returns an uncached record and logs a warning' do
diff --git a/spec/models/concerns/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb
index bb73dd8ade0..ad2c0770a2c 100644
--- a/spec/models/concerns/deployable_spec.rb
+++ b/spec/models/concerns/deployable_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Deployable do
describe '#create_deployment' do
diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb
index 27f535487c8..220f244ad71 100644
--- a/spec/models/concerns/deployment_platform_spec.rb
+++ b/spec/models/concerns/deployment_platform_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe DeploymentPlatform do
let(:project) { create(:project) }
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index cff86afe768..cad705ee594 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -66,6 +66,13 @@ describe Group, 'Routable' do
it { expect(described_class.find_by_full_path(group.to_param.upcase)).to eq(group) }
it { expect(described_class.find_by_full_path(nested_group.to_param)).to eq(nested_group) }
it { expect(described_class.find_by_full_path('unknown')).to eq(nil) }
+
+ it 'includes route information when loading a record' do
+ path = group.to_param
+ control_count = ActiveRecord::QueryRecorder.new { described_class.find_by_full_path(path) }.count
+
+ expect { described_class.find_by_full_path(path).route }.not_to exceed_all_query_limit(control_count)
+ end
end
context 'with redirect routes' do
diff --git a/spec/models/concerns/sha_attribute_spec.rb b/spec/models/concerns/sha_attribute_spec.rb
index a4a81ae126d..0d4dbfb215e 100644
--- a/spec/models/concerns/sha_attribute_spec.rb
+++ b/spec/models/concerns/sha_attribute_spec.rb
@@ -17,7 +17,7 @@ describe ShaAttribute do
describe '#sha_attribute' do
context 'when in non-production' do
before do
- allow(Rails.env).to receive(:production?).and_return(false)
+ stub_rails_env('development')
end
context 'when the table exists' do
@@ -76,7 +76,7 @@ describe ShaAttribute do
context 'when in production' do
before do
- allow(Rails.env).to receive(:production?).and_return(true)
+ stub_rails_env('production')
end
it 'defines a SHA attribute' do
diff --git a/spec/models/concerns/triggerable_hooks_spec.rb b/spec/models/concerns/triggerable_hooks_spec.rb
index f28e5f56411..ac1bc51d950 100644
--- a/spec/models/concerns/triggerable_hooks_spec.rb
+++ b/spec/models/concerns/triggerable_hooks_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe TriggerableHooks do
before do
diff --git a/spec/models/conversational_development_index/metric_spec.rb b/spec/models/conversational_development_index/metric_spec.rb
index 60b1a860dfd..55ba466e614 100644
--- a/spec/models/conversational_development_index/metric_spec.rb
+++ b/spec/models/conversational_development_index/metric_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe ConversationalDevelopmentIndex::Metric do
let(:conv_dev_index) { create(:conversational_development_index_metric) }
diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb
index 479b39cd139..b9c914e2506 100644
--- a/spec/models/gpg_key_spec.rb
+++ b/spec/models/gpg_key_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe GpgKey do
describe "associations" do
diff --git a/spec/models/gpg_key_subkey_spec.rb b/spec/models/gpg_key_subkey_spec.rb
index 51d2f9cb9ac..5f80cc02924 100644
--- a/spec/models/gpg_key_subkey_spec.rb
+++ b/spec/models/gpg_key_subkey_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe GpgKeySubkey do
subject { build(:gpg_key_subkey) }
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb
index 47c343edf0e..4911375c962 100644
--- a/spec/models/gpg_signature_spec.rb
+++ b/spec/models/gpg_signature_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe GpgSignature do
let(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' }
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index e0d4d2e4858..a4d202dc4f8 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -64,7 +64,7 @@ describe SystemHook do
).once
end
- it "project_create hook" do
+ it "project member create hook" do
project.add_maintainer(user)
expect(WebMock).to have_requested(:post, system_hook.url).with(
@@ -73,7 +73,7 @@ describe SystemHook do
).once
end
- it "project_destroy hook" do
+ it "project member destroy hook" do
project.add_maintainer(user)
project.project_members.destroy_all # rubocop: disable DestroyAll
@@ -83,6 +83,15 @@ describe SystemHook do
).once
end
+ it "project member update hook" do
+ project.add_guest(user)
+
+ expect(WebMock).to have_requested(:post, system_hook.url).with(
+ body: /user_update_for_team/,
+ headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'System Hook' }
+ ).once
+ end
+
it 'group create hook' do
create(:group)
@@ -119,6 +128,16 @@ describe SystemHook do
headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'System Hook' }
).once
end
+
+ it 'group member update hook' do
+ group.add_guest(user)
+ group.add_maintainer(user)
+
+ expect(WebMock).to have_requested(:post, system_hook.url).with(
+ body: /user_update_for_group/,
+ headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'System Hook' }
+ ).once
+ end
end
describe '.repository_update_hooks' do
diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb
index f812149c9be..85934b81086 100644
--- a/spec/models/hooks/web_hook_log_spec.rb
+++ b/spec/models/hooks/web_hook_log_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe WebHookLog do
it { is_expected.to belong_to(:web_hook) }
diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb
index 28630f7d3fe..c73ade3f896 100644
--- a/spec/models/internal_id_spec.rb
+++ b/spec/models/internal_id_spec.rb
@@ -106,7 +106,8 @@ describe InternalId do
end
it 'always attempts to generate internal IDs in production mode' do
- allow(Rails.env).to receive(:test?).and_return(false)
+ stub_rails_env('production')
+
val = rand(1..100)
generator = double(generate: val)
expect(InternalId::InternalIdGenerator).to receive(:new).and_return(generator)
diff --git a/spec/models/lfs_download_object_spec.rb b/spec/models/lfs_download_object_spec.rb
index 8b53effe98f..d7522fbb969 100644
--- a/spec/models/lfs_download_object_spec.rb
+++ b/spec/models/lfs_download_object_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe LfsDownloadObject do
let(:oid) { 'cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411' }
diff --git a/spec/models/lfs_file_lock_spec.rb b/spec/models/lfs_file_lock_spec.rb
index aa64d66944b..a42346c341d 100644
--- a/spec/models/lfs_file_lock_spec.rb
+++ b/spec/models/lfs_file_lock_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe LfsFileLock do
set(:lfs_file_lock) { create(:lfs_file_lock) }
diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb
index 2429cd408a6..dc28204d7aa 100644
--- a/spec/models/list_spec.rb
+++ b/spec/models/list_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe List do
it_behaves_like 'having unique enum values'
diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb
index 49573af0fed..bd97cabc11e 100644
--- a/spec/models/merge_request/metrics_spec.rb
+++ b/spec/models/merge_request/metrics_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
describe MergeRequest::Metrics do
- subject { described_class.new }
-
describe 'associations' do
it { is_expected.to belong_to(:merge_request) }
it { is_expected.to belong_to(:latest_closed_by).class_name('User') }
diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb
index ab2aadf7d88..c0a09dab0b0 100644
--- a/spec/models/merge_request_diff_commit_spec.rb
+++ b/spec/models/merge_request_diff_commit_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe MergeRequestDiffCommit do
let(:merge_request) { create(:merge_request) }
diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb
index 66957c24fdc..97b30bb8607 100644
--- a/spec/models/merge_request_diff_file_spec.rb
+++ b/spec/models/merge_request_diff_file_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe MergeRequestDiffFile do
describe '#diff' do
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index e7dd7287a75..b86663fd7d9 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -400,6 +400,18 @@ describe MergeRequestDiff do
end
end
+ describe '#first_commit' do
+ it 'returns first commit' do
+ expect(diff_with_commits.first_commit.sha).to eq(diff_with_commits.merge_request_diff_commits.last.sha)
+ end
+ end
+
+ describe '#last_commit' do
+ it 'returns last commit' do
+ expect(diff_with_commits.last_commit.sha).to eq(diff_with_commits.merge_request_diff_commits.first.sha)
+ end
+ end
+
describe '#commits_by_shas' do
let(:commit_shas) { diff_with_commits.commit_shas }
@@ -489,7 +501,7 @@ describe MergeRequestDiff do
subject { diff_with_commits }
it 'returns sum of all changed lines count in diff files' do
- expect(subject.lines_count).to eq 109
+ expect(subject.lines_count).to eq 189
end
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index d344a6d0f0d..11234982dd4 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -3195,6 +3195,40 @@ describe MergeRequest do
end
end
+ describe '.merge_train_ref?' do
+ subject { described_class.merge_train_ref?(ref) }
+
+ context 'when ref is ref name of a branch' do
+ let(:ref) { 'feature' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when ref is HEAD ref path of a branch' do
+ let(:ref) { 'refs/heads/feature' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when ref is HEAD ref path of a merge request' do
+ let(:ref) { 'refs/merge-requests/1/head' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when ref is merge ref path of a merge request' do
+ let(:ref) { 'refs/merge-requests/1/merge' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when ref is train ref path of a merge request' do
+ let(:ref) { 'refs/merge-requests/1/train' }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
describe '#cleanup_refs' do
subject { merge_request.cleanup_refs(only: only) }
diff --git a/spec/models/milestone_release_spec.rb b/spec/models/milestone_release_spec.rb
new file mode 100644
index 00000000000..d6f73275977
--- /dev/null
+++ b/spec/models/milestone_release_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe MilestoneRelease do
+ let(:project) { create(:project) }
+ let(:release) { create(:release, project: project) }
+ let(:milestone) { create(:milestone, project: project) }
+
+ subject { build(:milestone_release, release: release, milestone: milestone) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:milestone) }
+ it { is_expected.to belong_to(:release) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_uniqueness_of(:milestone_id).scoped_to(:release_id) }
+
+ context 'when milestone and release do not have the same project' do
+ it 'is not valid' do
+ other_project = create(:project)
+ release = build(:release, project: other_project)
+ milestone_release = described_class.new(milestone: milestone, release: release)
+ expect(milestone_release).not_to be_valid
+ end
+ end
+
+ context 'when milestone and release have the same project' do
+ it 'is valid' do
+ milestone_release = described_class.new(milestone: milestone, release: release)
+ expect(milestone_release).to be_valid
+ end
+ end
+ end
+end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 3704a2d468d..64030f5b92a 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -54,11 +54,31 @@ describe Milestone do
expect(milestone.errors[:due_date]).to include("date must not be after 9999-12-31")
end
end
+
+ describe 'milestone_release' do
+ let(:milestone) { build(:milestone, project: project) }
+
+ context 'when it is tied to a release for another project' do
+ it 'creates a validation error' do
+ other_project = create(:project)
+ milestone.release = build(:release, project: other_project)
+ expect(milestone).not_to be_valid
+ end
+ end
+
+ context 'when it is tied to a release for the same project' do
+ it 'is valid' do
+ milestone.release = build(:release, project: project)
+ expect(milestone).to be_valid
+ end
+ end
+ end
end
describe "Associations" do
it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:issues) }
+ it { is_expected.to have_one(:release) }
end
let(:project) { create(:project, :public) }
diff --git a/spec/models/note_diff_file_spec.rb b/spec/models/note_diff_file_spec.rb
index b15bedd257e..11108016b8e 100644
--- a/spec/models/note_diff_file_spec.rb
+++ b/spec/models/note_diff_file_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe NoteDiffFile do
describe 'associations' do
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index 85128456918..820d233dbdc 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe NotificationSetting do
it_behaves_like 'having unique enum values'
diff --git a/spec/models/project_deploy_token_spec.rb b/spec/models/project_deploy_token_spec.rb
index 2a5fefc1ab0..8c8924762bd 100644
--- a/spec/models/project_deploy_token_spec.rb
+++ b/spec/models/project_deploy_token_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe ProjectDeployToken, type: :model do
let(:project) { create(:project) }
diff --git a/spec/models/project_import_state_spec.rb b/spec/models/project_import_state_spec.rb
index 472bf8f9713..8a847bbe24e 100644
--- a/spec/models/project_import_state_spec.rb
+++ b/spec/models/project_import_state_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe ProjectImportState, type: :model do
subject { create(:import_state) }
diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb
index a164ed9bbea..4bc6130387a 100644
--- a/spec/models/project_statistics_spec.rb
+++ b/spec/models/project_statistics_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe ProjectStatistics do
let(:project) { create :project }
diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb
index 6ecb5c31c7e..b9b2873f8f2 100644
--- a/spec/models/redirect_route_spec.rb
+++ b/spec/models/redirect_route_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe RedirectRoute do
let(:group) { create(:group) }
diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb
index e9d846e7291..c690390e24d 100644
--- a/spec/models/release_spec.rb
+++ b/spec/models/release_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe Release do
let(:user) { create(:user) }
@@ -13,6 +13,7 @@ RSpec.describe Release do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:author).class_name('User') }
it { is_expected.to have_many(:links).class_name('Releases::Link') }
+ it { is_expected.to have_one(:milestone) }
end
describe 'validation' do
@@ -34,6 +35,20 @@ RSpec.describe Release do
expect(existing_release_without_name.name).to be_nil
end
end
+
+ context 'when a release is tied to a milestone for another project' do
+ it 'creates a validation error' do
+ release.milestone = build(:milestone, project: create(:project))
+ expect(release).not_to be_valid
+ end
+ end
+
+ context 'when a release is tied to a milestone linked to the same project' do
+ it 'is valid' do
+ release.milestone = build(:milestone, project: project)
+ expect(release).to be_valid
+ end
+ end
end
describe '#assets_count' do
diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb
index f8d6e500e10..63d0bf3f314 100644
--- a/spec/models/remote_mirror_spec.rb
+++ b/spec/models/remote_mirror_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe RemoteMirror, :mailer do
include GitHelpers
diff --git a/spec/models/resource_label_event_spec.rb b/spec/models/resource_label_event_spec.rb
index cb52f154299..f4023dcb95a 100644
--- a/spec/models/resource_label_event_spec.rb
+++ b/spec/models/resource_label_event_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe ResourceLabelEvent, type: :model do
subject { build(:resource_label_event, issue: issue) }
diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb
index 9d69a0ab148..28fc82f2a32 100644
--- a/spec/models/timelog_spec.rb
+++ b/spec/models/timelog_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
RSpec.describe Timelog do
subject { build(:timelog) }
diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb
index 02702cb2497..d97bb8cfb90 100644
--- a/spec/models/upload_spec.rb
+++ b/spec/models/upload_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Upload do
describe 'assocations' do
diff --git a/spec/models/user_agent_detail_spec.rb b/spec/models/user_agent_detail_spec.rb
index f191d245045..5c28511b446 100644
--- a/spec/models/user_agent_detail_spec.rb
+++ b/spec/models/user_agent_detail_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe UserAgentDetail do
describe '.submittable?' do
diff --git a/spec/models/user_callout_spec.rb b/spec/models/user_callout_spec.rb
index b87f6f03d6f..de6534b480a 100644
--- a/spec/models/user_callout_spec.rb
+++ b/spec/models/user_callout_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe UserCallout do
let!(:callout) { create(:user_callout) }
diff --git a/spec/policies/board_policy_spec.rb b/spec/policies/board_policy_spec.rb
index 52c23951e37..35eac8a02c4 100644
--- a/spec/policies/board_policy_spec.rb
+++ b/spec/policies/board_policy_spec.rb
@@ -56,4 +56,57 @@ describe BoardPolicy do
end
end
end
+
+ context 'create_non_backlog_issues' do
+ context 'for project boards' do
+ let!(:current_user) { create(:user) }
+
+ subject { described_class.new(current_user, project_board) }
+
+ context 'when user can admin project issues' do
+ it 'allows to add non backlog issues from issue board' do
+ project.add_reporter(current_user)
+
+ expect_allowed(:create_non_backlog_issues)
+ end
+ end
+
+ context 'when user cannot admin project issues' do
+ it 'does not allow to add non backlog issues from issue board' do
+ project.add_guest(current_user)
+
+ expect_disallowed(:create_non_backlog_issues)
+ end
+ end
+ end
+
+ context 'for group boards' do
+ let!(:current_user) { create(:user) }
+ let!(:project_1) { create(:project, namespace: group) }
+ let!(:project_2) { create(:project, namespace: group) }
+ let!(:group_board) { create(:board, group: group) }
+
+ subject { described_class.new(current_user, group_board) }
+
+ before do
+ project_1.add_guest(current_user)
+ end
+
+ context 'when user is at least reporter in one of the child projects' do
+ it 'allows to add non backlog issues from issue board' do
+ project_2.add_reporter(current_user)
+
+ expect_allowed(:create_non_backlog_issues)
+ end
+ end
+
+ context 'when user is not a reporter from any child projects' do
+ it 'does not allow to add non backlog issues from issue board' do
+ project_2.add_guest(current_user)
+
+ expect_disallowed(:create_non_backlog_issues)
+ end
+ end
+ end
+ end
end
diff --git a/spec/presenters/ci/pipeline_presenter_spec.rb b/spec/presenters/ci/pipeline_presenter_spec.rb
index cda07a0ae09..7e8bbedcf6d 100644
--- a/spec/presenters/ci/pipeline_presenter_spec.rb
+++ b/spec/presenters/ci/pipeline_presenter_spec.rb
@@ -77,6 +77,40 @@ describe Ci::PipelinePresenter do
end
end
+ describe '#name' do
+ subject { presenter.name }
+
+ context 'when pipeline is detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
+ let(:pipeline) { merge_request.all_pipelines.last }
+
+ it { is_expected.to eq('Detached merge request pipeline') }
+ end
+
+ context 'when pipeline is merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) }
+ let(:pipeline) { merge_request.all_pipelines.last }
+
+ it { is_expected.to eq('Merged result pipeline') }
+ end
+
+ context 'when pipeline is merge train pipeline' do
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+
+ before do
+ allow(pipeline).to receive(:merge_request_event_type) { :merge_train }
+ end
+
+ it { is_expected.to eq('Merge train pipeline') }
+ end
+
+ context 'when pipeline is branch pipeline' do
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+
+ it { is_expected.to eq('Pipeline') }
+ end
+ end
+
describe '#ref_text' do
subject { presenter.ref_text }
diff --git a/spec/presenters/clusterable_presenter_spec.rb b/spec/presenters/clusterable_presenter_spec.rb
index 05afe5347d1..47ccc59ae45 100644
--- a/spec/presenters/clusterable_presenter_spec.rb
+++ b/spec/presenters/clusterable_presenter_spec.rb
@@ -78,4 +78,13 @@ describe ClusterablePresenter do
it_behaves_like 'appropriate member permissions'
end
end
+
+ describe '#environments_cluster_path' do
+ subject { described_class.new(clusterable).environments_cluster_path(cluster) }
+
+ let(:clusterable) { create(:group) }
+ let(:cluster) { create(:cluster_for_group, groups: [clusterable]) }
+
+ it { is_expected.to be_nil }
+ end
end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
deleted file mode 100644
index 671fd6c8666..00000000000
--- a/spec/rails_helper.rb
+++ /dev/null
@@ -1 +0,0 @@
-require "spec_helper"
diff --git a/spec/requests/api/graphql/gitlab_schema_spec.rb b/spec/requests/api/graphql/gitlab_schema_spec.rb
index 28676bb02f4..e1eb7c7f738 100644
--- a/spec/requests/api/graphql/gitlab_schema_spec.rb
+++ b/spec/requests/api/graphql/gitlab_schema_spec.rb
@@ -120,7 +120,7 @@ describe 'GitlabSchema configurations' do
query_string: query,
variables: {}.to_s,
complexity: 181,
- depth: 0,
+ depth: 13,
duration: 7
}
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_wip_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_wip_spec.rb
index d75f0df9fd3..bbc477ba485 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_wip_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_wip_spec.rb
@@ -13,7 +13,16 @@ describe 'Setting WIP status of a merge request' do
project_path: project.full_path,
iid: merge_request.iid.to_s
}
- graphql_mutation(:merge_request_set_wip, variables.merge(input))
+ graphql_mutation(:merge_request_set_wip, variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ title
+ }
+ QL
+ )
end
def mutation_response
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 50f36141aed..0893dcb39b6 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -483,6 +483,22 @@ describe API::Groups do
describe "GET /groups/:id/projects" do
context "when authenticated as user" do
+ context 'with min access level' do
+ it 'returns projects with min access level or higher' do
+ group_guest = create(:user)
+ group1.add_guest(group_guest)
+ project4 = create(:project, group: group1)
+ project1.add_guest(group_guest)
+ project3.add_reporter(group_guest)
+ project4.add_developer(group_guest)
+
+ get api("/groups/#{group1.id}/projects", group_guest), params: { min_access_level: Gitlab::Access::REPORTER }
+
+ project_ids = json_response.map { |proj| proj['id'] }
+ expect(project_ids).to match_array([project3.id, project4.id])
+ end
+ end
+
it "returns the group's projects" do
get api("/groups/#{group1.id}/projects", user1)
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal/base_spec.rb
index c94f6d22e74..a56527073c7 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::Internal do
+describe API::Internal::Base do
set(:user) { create(:user) }
let(:key) { create(:key, user: user) }
set(:project) { create(:project, :repository, :wiki_repo) }
diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb
index 449032b95b7..326b724666d 100644
--- a/spec/requests/api/pages_domains_spec.rb
+++ b/spec/requests/api/pages_domains_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe API::PagesDomains do
set(:project) { create(:project, path: 'my.project', pages_https_only: false) }
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 58a28e636f1..2e6e13aa927 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe API::ProjectSnippets do
set(:project) { create(:project, :public) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 5465fe0c366..550c7d135a6 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -5,6 +5,8 @@ shared_examples 'languages and percentages JSON response' do
let(:expected_languages) { project.repository.languages.map { |language| language.values_at(:label, :value)}.to_h }
before do
+ allow(DetectRepositoryLanguagesWorker).to receive(:perform_async).and_call_original
+
allow(project.repository).to receive(:languages).and_return(
[{ value: 66.69, label: "Ruby", color: "#701516", highlight: "#701516" },
{ value: 22.98, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index cc05b8d5b45..515912cb305 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe API::Snippets do
let!(:user) { create(:user) }
diff --git a/spec/serializers/entity_date_helper_spec.rb b/spec/serializers/entity_date_helper_spec.rb
index ae0f917415c..73506954965 100644
--- a/spec/serializers/entity_date_helper_spec.rb
+++ b/spec/serializers/entity_date_helper_spec.rb
@@ -57,6 +57,28 @@ describe EntityDateHelper do
end
end
+ context 'when milestone due date is today' do
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words(Date.today) }
+
+ it 'returns today' do
+ expect(milestone_remaining).to eq("<strong>Today</strong>")
+ end
+ end
+
+ context 'when milestone due date is tomorrow' do
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words(Date.tomorrow) }
+
+ it 'returns 1 day remaining' do
+ expect(milestone_remaining).to eq("<strong>1</strong> day remaining")
+ end
+
+ it 'returns 1 day remaining when queried mid-day' do
+ Timecop.freeze(Time.utc(2017, 3, 17, 13, 10)) do
+ expect(milestone_remaining).to eq("<strong>1</strong> day remaining")
+ end
+ end
+ end
+
context 'when less than 1 year and more than 30 days remaining' do
let(:milestone_remaining) { date_helper_class.remaining_days_in_words(2.months.from_now.utc.to_date) }
diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb
index 6be612ec226..eb9972d3e4d 100644
--- a/spec/serializers/pipeline_entity_spec.rb
+++ b/spec/serializers/pipeline_entity_spec.rb
@@ -41,7 +41,7 @@ describe PipelineEntity do
it 'contains details' do
expect(subject).to include :details
expect(subject[:details])
- .to include :duration, :finished_at
+ .to include :duration, :finished_at, :name
expect(subject[:details][:status]).to include :icon, :favicon, :text, :label, :tooltip
end
@@ -211,6 +211,10 @@ describe PipelineEntity do
expect(subject[:source_sha]).to be_present
expect(subject[:target_sha]).to be_present
end
+
+ it 'exposes merge request event type' do
+ expect(subject[:merge_request_event_type]).to be_present
+ end
end
end
end
diff --git a/spec/services/audit_event_service_spec.rb b/spec/services/audit_event_service_spec.rb
index e42bff607b2..96df6689bb0 100644
--- a/spec/services/audit_event_service_spec.rb
+++ b/spec/services/audit_event_service_spec.rb
@@ -47,4 +47,16 @@ describe AuditEventService do
expect(details[:target_id]).to eq(1)
end
end
+
+ describe '#log_security_event_to_file' do
+ it 'logs security event to file' do
+ expect(service).to receive(:file_logger).and_return(logger)
+ expect(logger).to receive(:info).with(author_id: user.id,
+ entity_type: 'Project',
+ entity_id: project.id,
+ action: :destroy)
+
+ service.log_security_event_to_file
+ end
+ end
end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 3ca389ba25b..2807b8c8c85 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -476,7 +476,7 @@ describe Auth::ContainerRegistryAuthenticationService do
let(:current_user) { create(:user) }
let(:authentication_abilities) do
- [:build_read_container_image, :build_create_container_image]
+ [:build_read_container_image, :build_create_container_image, :build_destroy_container_image]
end
before do
@@ -507,19 +507,19 @@ describe Auth::ContainerRegistryAuthenticationService do
end
end
- context 'disallow to delete images' do
+ context 'allow to delete images since registry 2.7' do
let(:current_params) do
- { scopes: ["repository:#{current_project.full_path}:*"] }
+ { scopes: ["repository:#{current_project.full_path}:delete"] }
end
- it_behaves_like 'an inaccessible' do
+ it_behaves_like 'a deletable since registry 2.7' do
let(:project) { current_project }
end
end
- context 'disallow to delete images since registry 2.7' do
+ context 'disallow to delete images' do
let(:current_params) do
- { scopes: ["repository:#{current_project.full_path}:delete"] }
+ { scopes: ["repository:#{current_project.full_path}:*"] }
end
it_behaves_like 'an inaccessible' do
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index deb68899309..fad865a4811 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -1140,10 +1140,26 @@ describe Ci::CreatePipelineService do
context 'when pipeline on feature is created' do
let(:ref_name) { 'refs/heads/feature' }
- it 'does not create a pipeline as test_a depends on build_a' do
- expect(pipeline).not_to be_persisted
- expect(pipeline.builds).to be_empty
- expect(pipeline.errors[:base]).to contain_exactly("test_a: needs 'build_a'")
+ context 'when save_on_errors is enabled' do
+ let(:pipeline) { execute_service(save_on_errors: true) }
+
+ it 'does create a pipeline as test_a depends on build_a' do
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds).to be_empty
+ expect(pipeline.yaml_errors).to eq("test_a: needs 'build_a'")
+ expect(pipeline.errors[:base]).to contain_exactly("test_a: needs 'build_a'")
+ end
+ end
+
+ context 'when save_on_errors is disabled' do
+ let(:pipeline) { execute_service(save_on_errors: false) }
+
+ it 'does not create a pipeline as test_a depends on build_a' do
+ expect(pipeline).not_to be_persisted
+ expect(pipeline.builds).to be_empty
+ expect(pipeline.yaml_errors).to be_nil
+ expect(pipeline.errors[:base]).to contain_exactly("test_a: needs 'build_a'")
+ end
end
end
diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb
index 464a67649ff..02fd4b63c89 100644
--- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb
+++ b/spec/services/clusters/applications/check_installation_progress_service_spec.rb
@@ -142,7 +142,11 @@ describe Clusters::Applications::CheckInstallationProgressService, '#execute' do
end
it 'removes the installation POD' do
- expect(service).to receive(:remove_installation_pod).once
+ expect_any_instance_of(Gitlab::Kubernetes::Helm::Api)
+ .to receive(:delete_pod!)
+ .with(kind_of(String))
+ .once
+ expect(service).to receive(:remove_installation_pod).and_call_original
service.execute
end
diff --git a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
index 1a9f7089c3d..68ad0208226 100644
--- a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
+++ b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
@@ -47,11 +47,15 @@ describe Clusters::Applications::CheckUninstallProgressService do
context 'when installation POD succeeded' do
let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED }
before do
+ expect_any_instance_of(Gitlab::Kubernetes::Helm::Api)
+ .to receive(:delete_pod!)
+ .with(kind_of(String))
+ .once
expect(service).to receive(:pod_phase).once.and_return(phase)
end
it 'removes the installation POD' do
- expect(service).to receive(:remove_installation_pod).once
+ expect(service).to receive(:remove_uninstallation_pod).and_call_original
service.execute
end
@@ -76,7 +80,7 @@ describe Clusters::Applications::CheckUninstallProgressService do
end
it 'still removes the installation POD' do
- expect(service).to receive(:remove_installation_pod).once
+ expect(service).to receive(:remove_uninstallation_pod).and_call_original
service.execute
end
diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb
index f3af8cf5f3b..0cbb3122bb0 100644
--- a/spec/services/groups/transfer_service_spec.rb
+++ b/spec/services/groups/transfer_service_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Groups::TransferService do
let(:user) { create(:user) }
diff --git a/spec/services/metrics/dashboard/project_dashboard_service_spec.rb b/spec/services/metrics/dashboard/project_dashboard_service_spec.rb
index 1357914be2a..e76db868425 100644
--- a/spec/services/metrics/dashboard/project_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/project_dashboard_service_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe Metrics::Dashboard::ProjectDashboardService, :use_clean_rails_memory_store_caching do
include MetricsDashboardHelpers
diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb
index 3a22e4d4f92..ff1e1256166 100644
--- a/spec/services/milestones/destroy_service_spec.rb
+++ b/spec/services/milestones/destroy_service_spec.rb
@@ -65,5 +65,19 @@ describe Milestones::DestroyService do
expect { service.execute(group_milestone) }.not_to change { Event.count }
end
end
+
+ context 'when a release is tied to a milestone' do
+ it 'destroys the milestone but not the associated release' do
+ release = create(
+ :release,
+ tag: 'v1.0',
+ project: project,
+ milestone: milestone
+ )
+
+ expect { service.execute(milestone) }.not_to change { Release.count }
+ expect(release.reload).to be_persisted
+ end
+ end
end
end
diff --git a/spec/services/milestones/find_or_create_service_spec.rb b/spec/services/milestones/find_or_create_service_spec.rb
new file mode 100644
index 00000000000..ae3def30982
--- /dev/null
+++ b/spec/services/milestones/find_or_create_service_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Milestones::FindOrCreateService do
+ describe '#execute' do
+ subject(:service) { described_class.new(project, user, params) }
+
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+ let(:params) do
+ {
+ title: '1.0',
+ description: 'First Release',
+ start_date: Date.today,
+ due_date: Date.today + 1.month
+ }.with_indifferent_access
+ end
+
+ context 'when finding milestone on project level' do
+ let!(:existing_project_milestone) { create(:milestone, project: project, title: '1.0') }
+
+ it 'returns existing milestone' do
+ expect(service.execute).to eq(existing_project_milestone)
+ end
+ end
+
+ context 'when finding milestone on group level' do
+ let!(:existing_group_milestone) { create(:milestone, group: group, title: '1.0') }
+
+ it 'returns existing milestone' do
+ expect(service.execute).to eq(existing_group_milestone)
+ end
+ end
+
+ context 'when not finding milestone' do
+ context 'when user has permissions' do
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when params are valid' do
+ it 'creates a new milestone at project level using params' do
+ expect { service.execute }.to change(project.milestones, :count).by(1)
+
+ milestone = project.reload.milestones.last
+
+ expect(milestone.title).to eq(params[:title])
+ expect(milestone.description).to eq(params[:description])
+ expect(milestone.start_date).to eq(params[:start_date])
+ expect(milestone.due_date).to eq(params[:due_date])
+ end
+ end
+
+ context 'when params are not valid' do
+ before do
+ params[:start_date] = Date.today + 2.months
+ end
+
+ it 'returns nil' do
+ expect(service.execute).to be_nil
+ end
+ end
+ end
+
+ context 'when user does not have permissions' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'does not create a new milestone' do
+ expect { service.execute }.not_to change(project.milestones, :count)
+ end
+
+ it 'returns nil' do
+ expect(service.execute).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/milestones/transfer_service_spec.rb b/spec/services/milestones/transfer_service_spec.rb
new file mode 100644
index 00000000000..b3d41eb0763
--- /dev/null
+++ b/spec/services/milestones/transfer_service_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Milestones::TransferService do
+ describe '#execute' do
+ subject(:service) { described_class.new(user, old_group, project) }
+
+ context 'when old_group is present' do
+ let(:user) { create(:admin) }
+ let(:new_group) { create(:group) }
+ let(:old_group) { create(:group) }
+ let(:project) { create(:project, namespace: old_group) }
+ let(:group_milestone) { create(:milestone, group: old_group)}
+ let(:group_milestone2) { create(:milestone, group: old_group)}
+ let(:project_milestone) { create(:milestone, project: project)}
+ let!(:issue_with_group_milestone) { create(:issue, project: project, milestone: group_milestone) }
+ let!(:issue_with_project_milestone) { create(:issue, project: project, milestone: project_milestone) }
+ let!(:mr_with_group_milestone) { create(:merge_request, source_project: project, source_branch: 'branch-1', milestone: group_milestone) }
+ let!(:mr_with_project_milestone) { create(:merge_request, source_project: project, source_branch: 'branch-2', milestone: project_milestone) }
+
+ before do
+ new_group.add_maintainer(user)
+ project.add_maintainer(user)
+ # simulate project transfer
+ project.update(group: new_group)
+ end
+
+ context 'without existing milestone at the new group level' do
+ it 'recreates the missing group milestones at project level' do
+ expect { service.execute }.to change(project.milestones, :count).by(1)
+ end
+
+ it 'applies new project milestone to issues with group milestone' do
+ service.execute
+ new_milestone = issue_with_group_milestone.reload.milestone
+
+ expect(new_milestone).not_to eq(group_milestone)
+ expect(new_milestone.title).to eq(group_milestone.title)
+ expect(new_milestone.project_milestone?).to be_truthy
+ end
+
+ it 'does not apply new project milestone to issues with project milestone' do
+ service.execute
+
+ expect(issue_with_project_milestone.reload.milestone).to eq(project_milestone)
+ end
+
+ it 'applies new project milestone to merge_requests with group milestone' do
+ service.execute
+ new_milestone = mr_with_group_milestone.reload.milestone
+
+ expect(new_milestone).not_to eq(group_milestone)
+ expect(new_milestone.title).to eq(group_milestone.title)
+ expect(new_milestone.project_milestone?).to be_truthy
+ end
+
+ it 'does not apply new project milestone to issuables with project milestone' do
+ service.execute
+
+ expect(mr_with_project_milestone.reload.milestone).to eq(project_milestone)
+ end
+
+ it 'does not recreate missing group milestones that are not applied to issues or merge requests' do
+ service.execute
+ new_milestone_title = project.reload.milestones.pluck(:title)
+
+ expect(new_milestone_title).to include(group_milestone.title)
+ expect(new_milestone_title).not_to include(group_milestone2.title)
+ end
+
+ context 'when find_or_create_milestone returns nil' do
+ before do
+ allow_any_instance_of(Milestones::FindOrCreateService).to receive(:execute).and_return(nil)
+ end
+
+ it 'removes issues group milestone' do
+ service.execute
+
+ expect(mr_with_group_milestone.reload.milestone).to be_nil
+ end
+
+ it 'removes merge requests group milestone' do
+ service.execute
+
+ expect(issue_with_group_milestone.reload.milestone).to be_nil
+ end
+ end
+ end
+
+ context 'with existing milestone at the new group level' do
+ let!(:existing_milestone) { create(:milestone, group: new_group, title: group_milestone.title) }
+
+ it 'does not create a new milestone' do
+ expect { service.execute }.not_to change(project.milestones, :count)
+ end
+
+ it 'applies existing milestone to issues with group milestone' do
+ service.execute
+
+ expect(issue_with_group_milestone.reload.milestone).to eq(existing_milestone)
+ end
+
+ it 'applies existing milestone to merge_requests with group milestone' do
+ service.execute
+
+ expect(mr_with_group_milestone.reload.milestone).to eq(existing_milestone)
+ end
+ end
+ end
+ end
+
+ context 'when old_group is not present' do
+ let(:user) { create(:admin) }
+ let(:old_group) { project.group }
+ let(:project) { create(:project, namespace: user.namespace) }
+
+ it 'returns nil' do
+ expect(described_class.new(user, old_group, project).execute).to be_nil
+ end
+ end
+end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index ab0e01e27d7..bd6734634cb 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -278,6 +278,7 @@ describe NotificationService, :mailer do
notification.new_note(note)
should_email(note.author)
+ expect(find_email_for(note.author)).to have_header('X-GitLab-NotificationReason', 'own_activity')
end
it_behaves_like 'project emails are disabled' do
@@ -335,6 +336,9 @@ describe NotificationService, :mailer do
should_not_email(@u_participating)
should_not_email(@u_disabled)
should_not_email(@u_lazy_participant)
+
+ expect(find_email_for(@u_mentioned)).to have_header('X-GitLab-NotificationReason', 'mentioned')
+ expect(find_email_for(@u_custom_global)).to have_header('X-GitLab-NotificationReason', '')
end
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index a47c10d991a..6b906f9372c 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -259,7 +259,7 @@ describe Projects::TransferService do
end
context 'missing group labels applied to issues or merge requests' do
- it 'delegates tranfer to Labels::TransferService' do
+ it 'delegates transfer to Labels::TransferService' do
group.add_owner(user)
expect_any_instance_of(Labels::TransferService).to receive(:execute).once.and_call_original
@@ -268,6 +268,17 @@ describe Projects::TransferService do
end
end
+ context 'missing group milestones applied to issues or merge requests' do
+ it 'delegates transfer to Milestones::TransferService' do
+ group.add_owner(user)
+
+ expect(Milestones::TransferService).to receive(:new).with(user, project.group, project).and_call_original
+ expect_any_instance_of(Milestones::TransferService).to receive(:execute).once
+
+ transfer_project(project, user, group)
+ end
+ end
+
context 'when hashed storage in use' do
let(:hashed_project) { create(:project, :repository, namespace: user.namespace) }
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index c9714964fc9..6ca0a3fa448 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -970,34 +970,6 @@ describe QuickActions::InterpretService do
let(:issuable) { merge_request }
end
- it_behaves_like 'due command' do
- let(:content) { '/due 2016-08-28' }
- let(:issuable) { issue }
- end
-
- it_behaves_like 'due command' do
- let(:content) { '/due tomorrow' }
- let(:issuable) { issue }
- let(:expected_date) { Date.tomorrow }
- end
-
- it_behaves_like 'due command' do
- let(:content) { '/due 5 days from now' }
- let(:issuable) { issue }
- let(:expected_date) { 5.days.from_now.to_date }
- end
-
- it_behaves_like 'due command' do
- let(:content) { '/due in 2 days' }
- let(:issuable) { issue }
- let(:expected_date) { 2.days.from_now.to_date }
- end
-
- it_behaves_like 'empty command' do
- let(:content) { '/due foo bar' }
- let(:issuable) { issue }
- end
-
it_behaves_like 'empty command' do
let(:content) { '/due 2016-08-28' }
let(:issuable) { merge_request }
@@ -1131,6 +1103,39 @@ describe QuickActions::InterpretService do
end
end
+ context '/due command' do
+ it 'returns invalid date format message when the due date is invalid' do
+ issue = build(:issue, project: project)
+
+ _, _, message = service.execute('/due invalid date', issue)
+
+ expect(message).to eq('Failed to set due date because the date format is invalid.')
+ end
+
+ it_behaves_like 'due command' do
+ let(:content) { '/due 2016-08-28' }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'due command' do
+ let(:content) { '/due tomorrow' }
+ let(:issuable) { issue }
+ let(:expected_date) { Date.tomorrow }
+ end
+
+ it_behaves_like 'due command' do
+ let(:content) { '/due 5 days from now' }
+ let(:issuable) { issue }
+ let(:expected_date) { 5.days.from_now.to_date }
+ end
+
+ it_behaves_like 'due command' do
+ let(:content) { '/due in 2 days' }
+ let(:issuable) { issue }
+ let(:expected_date) { 2.days.from_now.to_date }
+ end
+ end
+
context '/copy_metadata command' do
let(:todo_label) { create(:label, project: project, title: 'To Do') }
let(:inreview_label) { create(:label, project: project, title: 'In Review') }
diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb
index e26676cdd55..5c9d6537df1 100644
--- a/spec/services/releases/create_service_spec.rb
+++ b/spec/services/releases/create_service_spec.rb
@@ -72,6 +72,15 @@ describe Releases::CreateService do
expect(project.releases.find_by(tag: tag_name).description).to eq(description)
end
end
+
+ context 'when a passed-in milestone does not exist for this project' do
+ it 'raises an error saying the milestone is inexistent' do
+ service = described_class.new(project, user, params.merge!({ milestone: 'v111.0' }))
+ result = service.execute
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq('Milestone does not exist')
+ end
+ end
end
describe '#find_or_build_release' do
@@ -80,5 +89,58 @@ describe Releases::CreateService do
expect(project.releases.count).to eq(0)
end
+
+ context 'when existing milestone is passed in' do
+ let(:title) { 'v1.0' }
+ let(:milestone) { create(:milestone, :active, project: project, title: title) }
+ let(:params_with_milestone) { params.merge!({ milestone: title }) }
+
+ it 'creates a release and ties this milestone to it' do
+ service = described_class.new(milestone.project, user, params_with_milestone)
+ result = service.execute
+
+ expect(project.releases.count).to eq(1)
+ expect(result[:status]).to eq(:success)
+
+ release = project.releases.last
+
+ expect(release.milestone).to eq(milestone)
+ end
+
+ context 'when another release was previously created with that same milestone linked' do
+ it 'also creates another release tied to that same milestone' do
+ other_release = create(:release, milestone: milestone, project: project, tag: 'v1.0')
+ service = described_class.new(milestone.project, user, params_with_milestone)
+ service.execute
+ release = project.releases.last
+
+ expect(release.milestone).to eq(milestone)
+ expect(other_release.milestone).to eq(milestone)
+ expect(release.id).not_to eq(other_release.id)
+ end
+ end
+ end
+
+ context 'when no milestone is passed in' do
+ it 'creates a release without a milestone tied to it' do
+ expect(params.key? :milestone).to be_falsey
+ service.execute
+ release = project.releases.last
+ expect(release.milestone).to be_nil
+ end
+
+ it 'does not create any new MilestoneRelease object' do
+ expect { service.execute }.not_to change { MilestoneRelease.count }
+ end
+ end
+
+ context 'when an empty value is passed as a milestone' do
+ it 'creates a release without a milestone tied to it' do
+ service = described_class.new(project, user, params.merge!({ milestone: '' }))
+ service.execute
+ release = project.releases.last
+ expect(release.milestone).to be_nil
+ end
+ end
end
end
diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb
index f4c901e6585..c3172e5edbc 100644
--- a/spec/services/releases/destroy_service_spec.rb
+++ b/spec/services/releases/destroy_service_spec.rb
@@ -57,5 +57,15 @@ describe Releases::DestroyService do
http_status: 403)
end
end
+
+ context 'when a milestone is tied to the release' do
+ let!(:milestone) { create(:milestone, :active, project: project, title: 'v1.0') }
+ let!(:release) { create(:release, milestone: milestone, project: project, tag: tag) }
+
+ it 'destroys the release but leave the milestone intact' do
+ expect { subject }.not_to change { Milestone.count }
+ expect(milestone.reload).to be_persisted
+ end
+ end
end
end
diff --git a/spec/services/releases/update_service_spec.rb b/spec/services/releases/update_service_spec.rb
index 14e6a5f13c8..944f3d8c9ad 100644
--- a/spec/services/releases/update_service_spec.rb
+++ b/spec/services/releases/update_service_spec.rb
@@ -48,5 +48,42 @@ describe Releases::UpdateService do
it_behaves_like 'a failed update'
end
+
+ context 'when a milestone is passed in' do
+ let(:old_title) { 'v1.0' }
+ let(:new_title) { 'v2.0' }
+ let(:milestone) { create(:milestone, project: project, title: old_title) }
+ let(:new_milestone) { create(:milestone, project: project, title: new_title) }
+ let(:params_with_milestone) { params.merge!({ milestone: new_title }) }
+
+ before do
+ release.milestone = milestone
+ release.save!
+
+ described_class.new(new_milestone.project, user, params_with_milestone).execute
+ release.reload
+ end
+
+ it 'updates the related milestone accordingly' do
+ expect(release.milestone.title).to eq(new_title)
+ end
+ end
+
+ context "when an 'empty' milestone is passed in" do
+ let(:milestone) { create(:milestone, project: project, title: 'v1.0') }
+ let(:params_with_empty_milestone) { params.merge!({ milestone: '' }) }
+
+ before do
+ release.milestone = milestone
+ release.save!
+
+ described_class.new(milestone.project, user, params_with_empty_milestone).execute
+ release.reload
+ end
+
+ it 'removes the old milestone and does not associate any new milestone' do
+ expect(release.milestone).to be_nil
+ end
+ end
end
end
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index f5c6e972953..d72e5cc2b16 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -19,6 +19,7 @@ describe SystemHooksService do
it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) }
it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) }
+ it { expect(event_data(project_member, :update)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) }
it { expect(event_data(key, :create)).to include(:username, :key, :id) }
it { expect(event_data(key, :destroy)).to include(:username, :key, :id) }
it { expect(event_data(deploy_key, :create)).to include(:key, :id) }
@@ -70,6 +71,13 @@ describe SystemHooksService do
)
end
+ it do
+ expect(event_data(group_member, :update)).to include(
+ :event_name, :created_at, :updated_at, :group_name, :group_path,
+ :group_id, :user_id, :user_username, :user_name, :user_email, :group_access
+ )
+ end
+
it 'includes the correct project visibility level' do
data = event_data(project, :create)
@@ -145,6 +153,7 @@ describe SystemHooksService do
it { expect(event_name(project, :update)).to eq "project_update" }
it { expect(event_name(project_member, :create)).to eq "user_add_to_team" }
it { expect(event_name(project_member, :destroy)).to eq "user_remove_from_team" }
+ it { expect(event_name(project_member, :update)).to eq "user_update_for_team" }
it { expect(event_name(key, :create)).to eq 'key_create' }
it { expect(event_name(key, :destroy)).to eq 'key_destroy' }
it { expect(event_name(group, :create)).to eq 'group_create' }
@@ -152,6 +161,7 @@ describe SystemHooksService do
it { expect(event_name(group, :rename)).to eq 'group_rename' }
it { expect(event_name(group_member, :create)).to eq 'user_add_to_group' }
it { expect(event_name(group_member, :destroy)).to eq 'user_remove_from_group' }
+ it { expect(event_name(group_member, :update)).to eq 'user_update_for_group' }
end
def event_data(*args)
diff --git a/spec/services/update_merge_request_metrics_service_spec.rb b/spec/services/update_merge_request_metrics_service_spec.rb
index 12a2b287c72..bb07dfa1a0e 100644
--- a/spec/services/update_merge_request_metrics_service_spec.rb
+++ b/spec/services/update_merge_request_metrics_service_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe MergeRequestMetricsService do
let(:metrics) { create(:merge_request).metrics }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index bd504f1553b..47f09bf14d0 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -109,6 +109,7 @@ RSpec.configure do |config|
config.include PolicyHelpers, type: :policy
config.include MemoryUsageHelper
config.include ExpectRequestWithStatus, type: :request
+ config.include RailsHelpers
if ENV['CI']
# This includes the first try, i.e. tests will be run 4 times before failing.
@@ -148,6 +149,12 @@ RSpec.configure do |config|
.with(:force_autodevops_on_by_default, anything)
.and_return(false)
+ # Stub this call due to being an expensive operation
+ # It can be reenabled for specific tests via:
+ #
+ # allow(DetectRepositoryLanguagesWorker).to receive(:perform_async).and_call_original
+ allow(DetectRepositoryLanguagesWorker).to receive(:perform_async).and_return(true)
+
Gitlab::ThreadMemoryCache.cache_backend.clear
end
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index d86371d70b9..beb346b2855 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -34,6 +34,14 @@ module GraphqlHelpers
end
end
+ # BatchLoader::GraphQL returns a wrapper, so we need to :sync in order
+ # to get the actual values
+ def batch_sync(max_queries: nil, &blk)
+ result = batch(max_queries: nil, &blk)
+
+ result.is_a?(Array) ? result.map(&:sync) : result&.sync
+ end
+
def graphql_query_for(name, attributes = {}, fields = nil)
<<~QUERY
{
@@ -114,7 +122,11 @@ module GraphqlHelpers
FIELDS
end
- def all_graphql_fields_for(class_name, parent_types = Set.new)
+ def all_graphql_fields_for(class_name, parent_types = Set.new, max_depth: 3)
+ # pulling _all_ fields can generate a _huge_ query (like complexity 180,000),
+ # and significantly increase spec runtime. so limit the depth by default
+ return if max_depth <= 0
+
allow_unlimited_graphql_complexity
allow_unlimited_graphql_depth
@@ -133,9 +145,9 @@ module GraphqlHelpers
if nested_fields?(field)
fields =
- all_graphql_fields_for(singular_field_type, parent_types | [type])
+ all_graphql_fields_for(singular_field_type, parent_types | [type], max_depth: max_depth - 1)
- "#{name} { #{fields} }"
+ "#{name} { #{fields} }" unless fields.blank?
else
name
end
diff --git a/spec/support/helpers/project_forks_helper.rb b/spec/support/helpers/project_forks_helper.rb
index b2d22853e4c..90d0d1845fc 100644
--- a/spec/support/helpers/project_forks_helper.rb
+++ b/spec/support/helpers/project_forks_helper.rb
@@ -45,7 +45,7 @@ module ProjectForksHelper
# not reset the @exists variable of this forked_project.repository
# so we have to explicitly call this method to clear the @exists variable.
# of the instance we're returning here.
- forked_project.repository.after_import
+ forked_project.repository.expire_content_cache
end
forked_project
diff --git a/spec/support/helpers/rails_helpers.rb b/spec/support/helpers/rails_helpers.rb
new file mode 100644
index 00000000000..e1875b2fb15
--- /dev/null
+++ b/spec/support/helpers/rails_helpers.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module RailsHelpers
+ def stub_rails_env(env_name)
+ allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new(env_name))
+ end
+end
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index a4acf76e1a3..8ca362ce2df 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -244,7 +244,6 @@ module TestEnv
FileUtils.mkdir_p(target_repo_path)
FileUtils.cp_r("#{File.expand_path(bare_repo)}/.", target_repo_path)
FileUtils.chmod_R 0755, target_repo_path
- set_repo_refs(target_repo_path, refs)
end
def create_bare_repository(path)
diff --git a/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb b/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
index 323d1c51ffd..9a60825855f 100644
--- a/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
@@ -46,7 +46,7 @@ shared_context 'exposing regular notes on a noteable in GraphQL' do
discussions {
edges {
node {
- #{all_graphql_fields_for('Discussion')}
+ #{all_graphql_fields_for('Discussion', max_depth: 4)}
}
}
}
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index e6e4d9504d9..2f3fc7839c1 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -57,7 +57,7 @@ describe 'gitlab:gitaly namespace rake task' do
stub_env('CI', false)
FileUtils.mkdir_p(clone_path)
expect(Dir).to receive(:chdir).with(clone_path).and_call_original
- allow(Rails.env).to receive(:test?).and_return(false)
+ stub_rails_env('development')
end
context 'gmake is available' do
@@ -93,7 +93,7 @@ describe 'gitlab:gitaly namespace rake task' do
end
before do
- allow(Rails.env).to receive(:test?).and_return(true)
+ stub_rails_env('test')
end
it 'calls make in the gitaly directory with --no-deployment flag for bundle' do
diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb
index 44718ed1212..3bee4875348 100644
--- a/spec/uploaders/gitlab_uploader_spec.rb
+++ b/spec/uploaders/gitlab_uploader_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
require 'carrierwave/storage/fog'
describe GitlabUploader do
diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb
index 6bad5d49b1c..0cf486c7087 100644
--- a/spec/uploaders/object_storage_spec.rb
+++ b/spec/uploaders/object_storage_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
require 'carrierwave/storage/fog'
class Implementation < GitlabUploader
diff --git a/spec/uploaders/records_uploads_spec.rb b/spec/uploaders/records_uploads_spec.rb
index 6134137d2b7..046ad3406d9 100644
--- a/spec/uploaders/records_uploads_spec.rb
+++ b/spec/uploaders/records_uploads_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe RecordsUploads do
let!(:uploader) do
diff --git a/spec/uploaders/uploader_helper_spec.rb b/spec/uploaders/uploader_helper_spec.rb
index fd6712d4645..7c9ec8ff59c 100644
--- a/spec/uploaders/uploader_helper_spec.rb
+++ b/spec/uploaders/uploader_helper_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe UploaderHelper do
let(:uploader) do
diff --git a/spec/validators/addressable_url_validator_spec.rb b/spec/validators/addressable_url_validator_spec.rb
index 387e84b2d04..6927a1f67a1 100644
--- a/spec/validators/addressable_url_validator_spec.rb
+++ b/spec/validators/addressable_url_validator_spec.rb
@@ -92,6 +92,15 @@ describe AddressableUrlValidator do
expect(badge.errors).to be_empty
expect(badge.link_url).to eq('https://127.0.0.1')
end
+
+ it 'allows urls that cannot be resolved' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+ badge.link_url = 'http://foobar.x'
+
+ subject
+
+ expect(badge.errors).to be_empty
+ end
end
context 'when message is set' do
@@ -312,4 +321,32 @@ describe AddressableUrlValidator do
end
end
end
+
+ context 'when dns_rebind_protection is' do
+ let(:not_resolvable_url) { 'http://foobar.x' }
+ let(:validator) { described_class.new(attributes: [:link_url], dns_rebind_protection: dns_value) }
+
+ before do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+ badge.link_url = not_resolvable_url
+
+ subject
+ end
+
+ context 'true' do
+ let(:dns_value) { true }
+
+ it 'raises error' do
+ expect(badge.errors).to be_present
+ end
+ end
+
+ context 'false' do
+ let(:dns_value) { false }
+
+ it 'allows urls that cannot be resolved' do
+ expect(badge.errors).to be_empty
+ end
+ end
+ end
end
diff --git a/spec/views/devise/shared/_signin_box.html.haml_spec.rb b/spec/views/devise/shared/_signin_box.html.haml_spec.rb
index 5d521d18c70..0563984a03c 100644
--- a/spec/views/devise/shared/_signin_box.html.haml_spec.rb
+++ b/spec/views/devise/shared/_signin_box.html.haml_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe 'devise/shared/_signin_box' do
describe 'Crowd form' do
diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb
index 257991549a9..f25e05dca7f 100644
--- a/spec/views/help/index.html.haml_spec.rb
+++ b/spec/views/help/index.html.haml_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe 'help/index' do
include StubVersion
diff --git a/spec/views/help/instance_configuration.html.haml_spec.rb b/spec/views/help/instance_configuration.html.haml_spec.rb
index ceb7e34a540..18628ddebf7 100644
--- a/spec/views/help/instance_configuration.html.haml_spec.rb
+++ b/spec/views/help/instance_configuration.html.haml_spec.rb
@@ -1,4 +1,4 @@
-require 'rails_helper'
+require 'spec_helper'
describe 'help/instance_configuration' do
describe 'General Sections:' do
diff --git a/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb b/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb
index ff2d491539b..697e44be065 100644
--- a/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb
+++ b/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb
@@ -17,10 +17,16 @@ describe 'projects/settings/ci_cd/_autodevops_form' do
context 'when the project has an available kubernetes cluster' do
let!(:cluster) { create(:cluster, cluster_type: :project_type, projects: [project]) }
- it 'does not show a warning message' do
+ it 'does not show a warning message about Kubernetes cluster' do
render
expect(rendered).not_to have_text('You must add a Kubernetes cluster')
end
+
+ it 'shows a warning message about base domain' do
+ render
+
+ expect(rendered).to have_text('You must add a base domain to your Kubernetes cluster in order for your deployment strategy to work.')
+ end
end
end
diff --git a/spec/views/projects/settings/operations/show.html.haml_spec.rb b/spec/views/projects/settings/operations/show.html.haml_spec.rb
index 6762fe3759b..ece9c16650f 100644
--- a/spec/views/projects/settings/operations/show.html.haml_spec.rb
+++ b/spec/views/projects/settings/operations/show.html.haml_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'spec_helper'
-require 'rails_helper'
describe 'projects/settings/operations/show' do
let(:project) { create(:project) }
diff --git a/spec/workers/repository_remove_remote_worker_spec.rb b/spec/workers/repository_remove_remote_worker_spec.rb
index 6eba5c50960..afac9212fab 100644
--- a/spec/workers/repository_remove_remote_worker_spec.rb
+++ b/spec/workers/repository_remove_remote_worker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe RepositoryRemoveRemoteWorker do
include ExclusiveLeaseHelpers
diff --git a/spec/workers/repository_update_remote_mirror_worker_spec.rb b/spec/workers/repository_update_remote_mirror_worker_spec.rb
index 66d517332ba..7bc499d480d 100644
--- a/spec/workers/repository_update_remote_mirror_worker_spec.rb
+++ b/spec/workers/repository_update_remote_mirror_worker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe RepositoryUpdateRemoteMirrorWorker, :clean_gitlab_redis_shared_state do
subject { described_class.new }
diff --git a/spec/workers/upload_checksum_worker_spec.rb b/spec/workers/upload_checksum_worker_spec.rb
index 7202c8001b4..ad054f0ff72 100644
--- a/spec/workers/upload_checksum_worker_spec.rb
+++ b/spec/workers/upload_checksum_worker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'rails_helper'
+require 'spec_helper'
describe UploadChecksumWorker do
describe '#perform' do
diff --git a/yarn.lock b/yarn.lock
index 4cf3a9584f1..92da409f544 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -996,10 +996,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.71.0.tgz#c8e6e8f500ea91e5cbba4ac08df533fb2e622a00"
integrity sha512-kkeNic/FFwaqKnzwio4NE7whBOZ/toRJ8cS0587DBotajAzSYhph5ij4TCY2GTjPa33zIJ5OUr/k90C0Kr71hQ==
-"@gitlab/ui@5.20.2":
- version "5.20.2"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.20.2.tgz#a51270d5a521e71059c5fd05f86cfc835f5e28ae"
- integrity sha512-TSaD5Cz0YXBTsRtQwsa7LbS2O5h0CL3YkdYmBKrMZkphL76xQaN08ZImkQ5Xl8cD1ZiWN2CsTvoUbF19UP2V1w==
+"@gitlab/ui@5.21.0":
+ version "5.21.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.21.0.tgz#975cf0bca3d16dd080d67ed392b9d24cd64695ac"
+ integrity sha512-8TMVM+pJXf7omHgKMMZ1FiltuyMOTwfQ3iFgorQzcuhio9u35DJpWi45S2TF7m6CrlpJi7dMX3BsXLbF7ViSUw==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"
@@ -2993,6 +2993,13 @@ commander@~2.17.1:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+commander@~2.9.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
+ integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=
+ dependencies:
+ graceful-readlink ">= 1.0.0"
+
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@@ -3890,6 +3897,11 @@ deep-extend@^0.6.0:
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+deep-extend@~0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f"
+ integrity sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==
+
deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@@ -4671,9 +4683,11 @@ eslint-scope@^4.0.0:
estraverse "^4.1.1"
eslint-utils@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512"
- integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
+ integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==
+ dependencies:
+ eslint-visitor-keys "^1.0.0"
eslint-visitor-keys@^1.0.0:
version "1.0.0"
@@ -4909,7 +4923,7 @@ exports-loader@^0.7.0:
express@^4.16.2, express@^4.16.3:
version "4.16.3"
- resolved "http://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
+ resolved "https://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
integrity sha1-avilAjUNsyRuzEvs9rWjTSL37VM=
dependencies:
accepts "~1.3.5"
@@ -5416,6 +5430,11 @@ get-stdin@^7.0.0:
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==
+get-stdin@~5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
+ integrity sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=
+
get-stream@3.0.0, get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -5532,7 +5551,7 @@ glob-to-regexp@^0.4.0:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
-"glob@5 - 7", glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1:
+"glob@5 - 7", glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1, glob@~7.1.2:
version "7.1.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
@@ -5724,6 +5743,11 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b"
integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==
+"graceful-readlink@>= 1.0.0":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
+ integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
+
graphlibrary@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/graphlibrary/-/graphlibrary-2.2.0.tgz#017a14899775228dec4497a39babfdd6bf56eac6"
@@ -7744,11 +7768,21 @@ lodash.debounce@^4.0.8:
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
+lodash.differencewith@~4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz#bafafbc918b55154e179176a00bb0aefaac854b7"
+ integrity sha1-uvr7yRi1UVTheRdqALsK76rIVLc=
+
lodash.escaperegexp@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=
+lodash.flatten@~4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+ integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
+
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
@@ -7933,6 +7967,17 @@ markdown-escapes@^1.0.0:
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.2.tgz#e639cbde7b99c841c0bacc8a07982873b46d2122"
integrity sha512-lbRZ2mE3Q9RtLjxZBZ9+IMl68DKIXaVAhwvwn9pmjnPLS0h/6kyBMgNhqi1xFJ/2yv6cSyv0jbiZavZv93JkkA==
+markdown-it@9.0.1:
+ version "9.0.1"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-9.0.1.tgz#aafe363c43718720b6575fd10625cde6e4ff2d47"
+ integrity sha512-XC9dMBHg28Xi7y5dPuLjM61upIGPJG8AiHNHYqIaXER2KNnn7eKnM5/sF0ImNnyoV224Ogn9b1Pck8VH4k0bxw==
+ dependencies:
+ argparse "^1.0.7"
+ entities "~1.1.1"
+ linkify-it "^2.0.0"
+ mdurl "^1.0.1"
+ uc.micro "^1.0.5"
+
markdown-it@^8.4.2:
version "8.4.2"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54"
@@ -7949,6 +7994,29 @@ markdown-table@^1.1.0:
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.2.tgz#c78db948fa879903a41bce522e3b96f801c63786"
integrity sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw==
+markdownlint-cli@0.18.0:
+ version "0.18.0"
+ resolved "https://registry.yarnpkg.com/markdownlint-cli/-/markdownlint-cli-0.18.0.tgz#bd1cee72739049d42dcea5f6db0c0f57c6eb8096"
+ integrity sha512-mQ2zvjMLoy0P2kb9Y03SqC24WPH4fTRN0/CyCorB122c4Chg9vWJKgUKBz3KR7swpzqmlI0SYq/7Blbqe4kb2g==
+ dependencies:
+ commander "~2.9.0"
+ deep-extend "~0.5.1"
+ get-stdin "~5.0.1"
+ glob "~7.1.2"
+ js-yaml "^3.13.1"
+ lodash.differencewith "~4.5.0"
+ lodash.flatten "~4.4.0"
+ markdownlint "~0.16.0"
+ minimatch "~3.0.4"
+ rc "~1.2.7"
+
+markdownlint@~0.16.0:
+ version "0.16.0"
+ resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.16.0.tgz#69f73cc755a44231fbe5dc7c37a5909cedc0ac6e"
+ integrity sha512-Zo+iPezP3eM6lLhKepkUw+X98H44lipIdx4d6faaugfB0+7VuDB3R0hXmx7z9F1N3/ypn46oOFgAD9iF++Ie6A==
+ dependencies:
+ markdown-it "9.0.1"
+
marked@^0.3.12, marked@~0.3.6:
version "0.3.19"
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790"
@@ -8233,7 +8301,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
+minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2, minimatch@~3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -8304,7 +8372,7 @@ mixin-deep@^1.2.0:
mkdirp@0.5.x, mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1"
- resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
dependencies:
minimist "0.0.8"
@@ -9931,7 +9999,7 @@ raw-loader@^1.0.0:
loader-utils "^1.1.0"
schema-utils "^1.0.0"
-rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
+rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@~1.2.7:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==