summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dockerignore10
-rw-r--r--.gitlab-ci.yml26
-rw-r--r--.gitlab/CODEOWNERS13
-rw-r--r--.gitlab/ci/cng.gitlab-ci.yml7
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml49
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml167
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml102
-rw-r--r--.gitlab/ci/memory.gitlab-ci.yml17
-rw-r--r--.gitlab/ci/pages.gitlab-ci.yml21
-rw-r--r--.gitlab/ci/qa.gitlab-ci.yml13
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml288
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml34
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml129
-rw-r--r--.gitlab/ci/setup.gitlab-ci.yml45
-rw-r--r--.gitlab/ci/test-metadata.gitlab-ci.yml30
-rw-r--r--.gitlab/ci/yaml.gitlab-ci.yml7
-rw-r--r--.markdownlint.json31
-rw-r--r--.mdlrc7
-rw-r--r--.mdlrc.style32
-rw-r--r--.rubocop.yml54
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock12
-rw-r--r--app/assets/javascripts/lib/utils/http_status.js1
-rw-r--r--app/assets/javascripts/monitoring/components/charts/time_series.vue10
-rw-r--r--app/assets/javascripts/monitoring/components/embed.vue6
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue8
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue31
-rw-r--r--app/assets/javascripts/notes/stores/actions.js22
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue4
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment.js39
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js31
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment_post.js145
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment_storage.js20
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/form_elements.js17
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/index.js23
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/login.js47
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/mr_id.js63
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/note.js35
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/utils.js51
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/wrapper.js79
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/wrapper_icons.js15
-rw-r--r--app/assets/javascripts/visual_review_toolbar/index.js51
-rw-r--r--app/assets/javascripts/visual_review_toolbar/shared/constants.js56
-rw-r--r--app/assets/javascripts/visual_review_toolbar/shared/index.js55
-rw-r--r--app/assets/javascripts/visual_review_toolbar/shared/storage_utils.js42
-rw-r--r--app/assets/javascripts/visual_review_toolbar/store/events.js73
-rw-r--r--app/assets/javascripts/visual_review_toolbar/store/index.js11
-rw-r--r--app/assets/javascripts/visual_review_toolbar/store/state.js95
-rw-r--r--app/assets/javascripts/visual_review_toolbar/store/utils.js15
-rw-r--r--app/assets/javascripts/visual_review_toolbar/styles/toolbar.css188
-rw-r--r--app/controllers/concerns/notes_actions.rb5
-rw-r--r--app/controllers/jwt_controller.rb1
-rw-r--r--app/controllers/projects/notes_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb2
-rw-r--r--app/graphql/functions/base_function.rb6
-rw-r--r--app/graphql/functions/echo.rb15
-rw-r--r--app/graphql/gitlab_schema.rb2
-rw-r--r--app/graphql/resolvers/echo_resolver.rb14
-rw-r--r--app/graphql/types/query_type.rb2
-rw-r--r--app/helpers/ci_status_helper.rb3
-rw-r--r--app/helpers/notifications_helper.rb4
-rw-r--r--app/models/analytics/cycle_analytics/project_stage.rb5
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stage.rb68
-rw-r--r--app/models/deploy_token.rb2
-rw-r--r--app/models/deployment.rb8
-rw-r--r--app/models/project.rb3
-rw-r--r--app/models/user.rb12
-rw-r--r--app/policies/project_policy.rb2
-rw-r--r--app/serializers/deployment_entity.rb2
-rw-r--r--app/services/application_settings/update_service.rb6
-rw-r--r--app/services/merge_requests/create_service.rb1
-rw-r--r--app/services/notes/update_service.rb66
-rw-r--r--app/services/self_monitoring/project/create_service.rb219
-rw-r--r--app/views/ci/status/_icon.html.haml3
-rw-r--r--app/views/layouts/_piwik.html.haml4
-rw-r--r--app/views/profiles/preferences/show.html.haml2
-rw-r--r--app/views/projects/deployments/_deployment.html.haml4
-rw-r--r--app/views/projects/mirrors/_mirror_repos.html.haml2
-rw-r--r--app/views/projects/serverless/functions/index.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml4
-rw-r--r--app/views/shared/projects/_project.html.haml2
-rw-r--r--changelogs/unreleased/21505-quickactions-update-pd.yml5
-rw-r--r--changelogs/unreleased/55360-redundant-index-in-the-releases-table_v2.yml5
-rw-r--r--changelogs/unreleased/55999-misleading-pipeline-tooltip-messages-and-misleading-ci-status-icons.yml5
-rw-r--r--changelogs/unreleased/56883-migration.yml5
-rw-r--r--changelogs/unreleased/63502-encrypt-deploy-token.yml5
-rw-r--r--changelogs/unreleased/64269-pipeline-api-fails-with-401.yml5
-rw-r--r--changelogs/unreleased/64764-fix-serverless-layout.yml5
-rw-r--r--changelogs/unreleased/66037-deployment-user.yml5
-rw-r--r--changelogs/unreleased/66073-use-time-series-chart-instead-of-area-chart-in-panel_types.yml5
-rw-r--r--changelogs/unreleased/66402-use-visual-review-tools-npm-package.yml5
-rw-r--r--changelogs/unreleased/66443-unrecoverable-configuration-loop-in-external-auth-control.yml5
-rw-r--r--changelogs/unreleased/fe-fix-issuable-sidebar-icon-of-notification-disabled.yml5
-rw-r--r--changelogs/unreleased/georgekoltsov-54023-fogbugz-visibility-level.yml5
-rw-r--r--changelogs/unreleased/id-code-review-smau.yml5
-rw-r--r--changelogs/unreleased/oauth_bypass_two_factor.yml5
-rw-r--r--changelogs/unreleased/sh-fix-nplusone-issues.yml5
-rw-r--r--changelogs/unreleased/sh-fix-piwik-template.yml5
-rw-r--r--changelogs/unreleased/sh-guard-against-orphaned-project-feature.yml5
-rw-r--r--changelogs/unreleased/user_name_migration.yml5
-rw-r--r--config/gitlab.yml.example8
-rw-r--r--config/initializers/1_settings.rb1
-rw-r--r--config/webpack.config.js7
-rw-r--r--config/webpack.config.review_toolbar.js58
-rw-r--r--danger/only_documentation/Dangerfile2
-rw-r--r--db/migrate/20171230123729_init_schema.rb2
-rw-r--r--db/migrate/20180101160629_create_prometheus_metrics.rb2
-rw-r--r--db/migrate/20180122162010_add_auto_devops_domain_to_application_settings.rb2
-rw-r--r--db/migrate/20180129193323_add_uploads_builder_context.rb2
-rw-r--r--db/migrate/20180212030105_add_external_ip_to_clusters_applications_ingress.rb2
-rw-r--r--db/migrate/20180214093516_create_badges.rb2
-rw-r--r--db/migrate/20180214155405_create_clusters_applications_runners.rb2
-rw-r--r--db/migrate/20180216120000_add_pages_domain_verification.rb2
-rw-r--r--db/migrate/20180222043024_add_ip_address_to_runner.rb2
-rw-r--r--db/migrate/20180308125206_add_user_internal_regex_to_application_setting.rb2
-rw-r--r--db/migrate/20180315160435_add_external_auth_mutual_tls_fields_to_project_settings.rb2
-rw-r--r--db/migrate/20180319190020_create_deploy_tokens.rb2
-rw-r--r--db/migrate/20180502122856_create_project_mirror_data.rb2
-rw-r--r--db/migrate/20180503131624_create_remote_mirrors.rb2
-rw-r--r--db/migrate/20180503175053_ensure_missing_columns_to_project_mirror_data.rb4
-rw-r--r--db/migrate/20180511131058_create_clusters_applications_jupyter.rb6
-rw-r--r--db/migrate/20180515121227_create_notes_diff_files.rb2
-rw-r--r--db/migrate/20180529093006_ensure_remote_mirror_columns.rb2
-rw-r--r--db/migrate/20180531185349_add_repository_languages.rb2
-rw-r--r--db/migrate/20180613081317_create_ci_builds_runner_session.rb2
-rw-r--r--db/migrate/20180713092803_create_user_statuses.rb2
-rw-r--r--db/migrate/20180814153625_add_commit_email_to_users.rb2
-rw-r--r--db/migrate/20180831164908_add_identifier_to_prometheus_metric.rb2
-rw-r--r--db/migrate/20180910115836_add_attr_encrypted_columns_to_web_hook.rb2
-rw-r--r--db/migrate/20180910153412_add_token_digest_to_personal_access_tokens.rb2
-rw-r--r--db/migrate/20180912111628_add_knative_application.rb2
-rw-r--r--db/migrate/20181009190428_create_clusters_kubernetes_namespaces.rb2
-rw-r--r--db/migrate/20181019032400_add_shards_table.rb2
-rw-r--r--db/migrate/20181019032408_add_repositories_table.rb2
-rw-r--r--db/migrate/20181025115728_add_private_commit_email_hostname_to_application_settings.rb2
-rw-r--r--db/migrate/20181031190559_drop_gcp_clusters_table.rb2
-rw-r--r--db/migrate/20181101191341_create_clusters_applications_cert_manager.rb2
-rw-r--r--db/migrate/20181115140140_add_encrypted_runners_token_to_settings.rb2
-rw-r--r--db/migrate/20181116050532_knative_external_ip.rb2
-rw-r--r--db/migrate/20181116141415_add_encrypted_runners_token_to_namespaces.rb2
-rw-r--r--db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb2
-rw-r--r--db/migrate/20181120151656_add_token_encrypted_to_ci_runners.rb2
-rw-r--r--db/migrate/20181122160027_create_project_repositories.rb2
-rw-r--r--db/migrate/20181123144235_create_suggestions.rb2
-rw-r--r--db/migrate/20181128123704_add_state_to_pool_repository.rb2
-rw-r--r--db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb2
-rw-r--r--db/migrate/20181203002526_add_project_bfg_object_map_column.rb2
-rw-r--r--db/migrate/20181211092510_add_name_author_id_and_sha_to_releases.rb4
-rw-r--r--db/migrate/20181212171634_create_error_tracking_settings.rb2
-rw-r--r--db/migrate/20181228175414_create_releases_link_table.rb2
-rw-r--r--db/migrate/20190109153125_add_merge_request_external_diffs.rb2
-rw-r--r--db/migrate/20190114172110_add_domain_to_cluster.rb2
-rw-r--r--db/migrate/20190115092821_add_columns_project_error_tracking_settings.rb4
-rw-r--r--db/migrate/20190116234221_add_sorting_fields_to_user_preference.rb4
-rw-r--r--db/migrate/20190301182457_add_external_hostname_to_ingress_and_knative.rb4
-rw-r--r--db/migrate/20190320174702_add_lets_encrypt_notification_email_to_application_settings.rb2
-rw-r--r--db/migrate/20190325105715_add_fields_to_user_preferences.rb2
-rw-r--r--db/migrate/20190327163904_add_notification_email_to_notification_settings.rb2
-rw-r--r--db/migrate/20190402150158_backport_enterprise_schema.rb2
-rw-r--r--db/migrate/20190409224933_add_name_to_geo_nodes.rb2
-rw-r--r--db/migrate/20190422082247_create_project_metrics_settings.rb2
-rw-r--r--db/migrate/20190429082448_create_pages_domain_acme_orders.rb2
-rw-r--r--db/migrate/20190430131225_create_issue_tracker_data.rb2
-rw-r--r--db/migrate/20190430142025_create_jira_tracker_data.rb2
-rw-r--r--db/migrate/20190514105711_create_ip_restriction.rb2
-rw-r--r--db/migrate/20190527011309_add_required_template_name_to_application_settings.rb2
-rw-r--r--db/migrate/20190606054742_add_token_encrypted_to_operations_feature_flags_clients.rb2
-rw-r--r--db/migrate/20190613044655_add_username_to_deploy_tokens.rb2
-rw-r--r--db/migrate/20190613073003_create_project_aliases.rb2
-rw-r--r--db/migrate/20190621151636_add_merge_request_rebase_jid.rb2
-rw-r--r--db/migrate/20190624123615_add_grafana_url_to_settings.rb2
-rw-r--r--db/migrate/20190711124721_create_job_variables.rb2
-rw-r--r--db/migrate/20190711200053_change_deploy_tokens_token_not_null.rb11
-rw-r--r--db/migrate/20190711200508_add_token_encrypted_to_deploy_tokens.rb11
-rw-r--r--db/migrate/20190719174505_add_index_to_deploy_tokens_token_encrypted.rb17
-rw-r--r--db/migrate/20190726101050_rename_allow_local_requests_from_hooks_and_services_application_setting.rb2
-rw-r--r--db/migrate/20190805140353_remove_rendundant_index_from_releases.rb21
-rw-r--r--db/migrate/20190820163320_add_first_last_name_to_user.rb14
-rw-r--r--db/post_migrate/20181013005024_remove_koding_from_application_settings.rb2
-rw-r--r--db/post_migrate/20190404231137_remove_alternate_url_from_geo_nodes.rb2
-rw-r--r--db/post_migrate/20190625184066_remove_sentry_from_application_settings.rb2
-rw-r--r--db/post_migrate/20190711201818_encrypt_deploy_tokens_tokens.rb27
-rw-r--r--db/post_migrate/20190801072937_add_gitlab_instance_administration_project.rb16
-rw-r--r--db/post_migrate/20190801114109_cleanup_allow_local_requests_from_hooks_and_services_application_setting_rename.rb2
-rw-r--r--db/post_migrate/20190809072552_set_self_monitoring_project_alerting_token.rb73
-rw-r--r--db/schema.rb9
-rw-r--r--doc/administration/database_load_balancing.md7
-rw-r--r--doc/administration/gitaly/index.md63
-rw-r--r--doc/administration/issue_closing_pattern.md17
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md326
-rw-r--r--doc/administration/repository_storage_types.md12
-rw-r--r--doc/administration/smime_signing_email.md2
-rw-r--r--doc/api/events.md12
-rw-r--r--doc/api/issues.md1
-rw-r--r--doc/api/projects.md8
-rw-r--r--doc/ci/caching/index.md23
-rw-r--r--doc/ci/yaml/README.md122
-rw-r--r--doc/development/changelog.md1
-rw-r--r--doc/development/documentation/feature-change-workflow.md2
-rw-r--r--doc/development/emails.md2
-rw-r--r--doc/development/git_object_deduplication.md24
-rw-r--r--doc/development/namespaces_storage_statistics.md24
-rw-r--r--doc/development/uploads.md11
-rw-r--r--doc/gitlab-basics/start-using-git.md6
-rw-r--r--doc/integration/omniauth.md21
-rw-r--r--doc/raketasks/backup_restore.md23
-rw-r--r--doc/security/README.md1
-rw-r--r--doc/security/password_storage.md13
-rw-r--r--doc/topics/autodevops/index.md5
-rw-r--r--doc/user/admin_area/monitoring/health_check.md8
-rw-r--r--doc/user/application_security/container_scanning/index.md32
-rw-r--r--doc/user/application_security/dependency_scanning/index.md36
-rw-r--r--doc/user/application_security/license_management/index.md8
-rw-r--r--doc/user/application_security/sast/analyzers.md2
-rw-r--r--doc/user/application_security/sast/index.md16
-rw-r--r--doc/user/index.md2
-rw-r--r--doc/user/project/index.md4
-rw-r--r--doc/user/project/integrations/prometheus.md2
-rw-r--r--doc/user/project/issue_board.md30
-rw-r--r--doc/workflow/forking/branch_select.pngbin15410 -> 18042 bytes
-rw-r--r--doc/workflow/forking/merge_request.pngbin16329 -> 24625 bytes
-rw-r--r--doc/workflow/forking_workflow.md7
-rw-r--r--doc/workflow/img/forking_workflow_choose_namespace.pngbin26275 -> 35084 bytes
-rw-r--r--doc/workflow/img/forking_workflow_fork_button.pngbin12962 -> 25754 bytes
-rw-r--r--doc/workflow/img/forking_workflow_path_taken_error.pngbin10092 -> 21497 bytes
-rw-r--r--lib/api/issues.rb3
-rw-r--r--lib/api/pipelines.rb3
-rw-r--r--lib/feature/gitaly.rb1
-rw-r--r--lib/gitlab/analytics/cycle_analytics/default_stages.rb98
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events.rb71
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/issue_created.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb23
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/simple_stage_event.rb13
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb28
-rw-r--r--lib/gitlab/auth.rb5
-rw-r--r--lib/gitlab/auth/o_auth/user.rb7
-rw-r--r--lib/gitlab/danger/helper.rb1
-rw-r--r--lib/gitlab/database.rb3
-rw-r--r--lib/gitlab/database/migration_helpers.rb46
-rw-r--r--lib/gitlab/database_importers/self_monitoring/project/create_service.rb249
-rw-r--r--lib/gitlab/fogbugz_import/project_creator.rb2
-rw-r--r--lib/gitlab/graphql/present/instrumentation.rb4
-rw-r--r--lib/gitlab/usage_data.rb3
-rw-r--r--lib/gitlab/usage_data_counters/merge_request_counter.rb10
-rw-r--r--lib/tasks/gitlab/assets.rake6
-rw-r--r--locale/gitlab.pot67
-rw-r--r--package.json8
-rw-r--r--qa/Dockerfile2
-rw-r--r--qa/qa.rb7
-rw-r--r--qa/qa/service/cluster_provider/base.rb41
-rw-r--r--qa/qa/service/cluster_provider/gcloud.rb87
-rw-r--r--qa/qa/service/cluster_provider/k3d.rb131
-rw-r--r--qa/qa/service/cluster_provider/minikube.rb26
-rw-r--r--qa/qa/service/kubernetes_cluster.rb134
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb3
-rw-r--r--rubocop/cop/gitlab/httparty.rb6
-rw-r--r--rubocop/cop/gitlab/union.rb4
-rw-r--r--rubocop/cop/graphql/authorize_types.rb6
-rw-r--r--rubocop/cop/include_action_view_context.rb5
-rw-r--r--rubocop/cop/include_sidekiq_worker.rb5
-rw-r--r--rubocop/cop/migration/add_limit_to_string_columns.rb59
-rw-r--r--rubocop/cop/rspec/env_assignment.rb5
-rw-r--r--rubocop/cop/rspec/factories_in_migration_specs.rb5
-rw-r--r--rubocop/cop/sidekiq_options_queue.rb5
-rw-r--r--rubocop/rubocop.rb1
-rw-r--r--rubocop/spec_helpers.rb30
-rw-r--r--spec/factories/ci/job_artifacts.rb4
-rw-r--r--spec/factories/deploy_tokens.rb3
-rw-r--r--spec/features/dashboard/projects_spec.rb4
-rw-r--r--spec/features/oauth_login_spec.rb12
-rw-r--r--spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb2
-rw-r--r--spec/frontend/monitoring/embed/embed_spec.js8
-rw-r--r--spec/graphql/resolvers/echo_resolver_spec.rb24
-rw-r--r--spec/helpers/ci_status_helper_spec.rb76
-rw-r--r--spec/javascripts/monitoring/panel_type_spec.js7
-rw-r--r--spec/javascripts/notes/stores/actions_spec.js45
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb10
-rw-r--r--spec/lib/gitlab/auth/o_auth/user_spec.rb22
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb114
-rw-r--r--spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb (renamed from spec/services/self_monitoring/project/create_service_spec.rb)123
-rw-r--r--spec/lib/gitlab/database_spec.rb11
-rw-r--r--spec/lib/gitlab/fogbugz_import/project_creator_spec.rb29
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb5
-rw-r--r--spec/lib/gitlab/graphql/markdown_field_spec.rb7
-rw-r--r--spec/lib/gitlab/usage_data_counters/merge_request_counter_spec.rb9
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb1
-rw-r--r--spec/migrations/add_gitlab_instance_administration_project_spec.rb252
-rw-r--r--spec/migrations/encrypt_deploy_tokens_tokens_spec.rb47
-rw-r--r--spec/models/analytics/cycle_analytics/project_stage_spec.rb14
-rw-r--r--spec/models/deployment_spec.rb26
-rw-r--r--spec/models/project_spec.rb31
-rw-r--r--spec/models/user_spec.rb20
-rw-r--r--spec/policies/project_policy_spec.rb13
-rw-r--r--spec/requests/api/graphql/multiplexed_queries_spec.rb8
-rw-r--r--spec/requests/api/issues/get_project_issues_spec.rb8
-rw-r--r--spec/requests/api/pipelines_spec.rb11
-rw-r--r--spec/requests/jwt_controller_spec.rb8
-rw-r--r--spec/rubocop/cop/gitlab/union_spec.rb6
-rw-r--r--spec/rubocop/cop/migration/add_limit_to_string_columns_spec.rb268
-rw-r--r--spec/rubocop/cop/rspec/env_assignment_spec.rb26
-rw-r--r--spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb22
-rw-r--r--spec/services/application_settings/update_service_spec.rb18
-rw-r--r--spec/services/merge_requests/create_service_spec.rb8
-rw-r--r--spec/support/helpers/stub_configuration.rb4
-rw-r--r--spec/support/shared_examples/cycle_analytics_stage_examples.rb74
-rw-r--r--spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb49
-rw-r--r--spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb235
-rw-r--r--spec/views/layouts/_head.html.haml_spec.rb20
-rw-r--r--yarn.lock21
318 files changed, 4605 insertions, 2729 deletions
diff --git a/.dockerignore b/.dockerignore
index b8e239e4049..4f5b33de167 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -4,6 +4,7 @@
# the files we need to build the QA image are in these folders.
# Following are the files we need:
# - ./config/initializers/0_inject_enterprise_edition_module.rb
+# - ./ee/app/models/license.rb
# - ./lib/gitlab.rb
# - ./qa/
# - ./INSTALLATION_TYPE
@@ -23,7 +24,14 @@
/db/
/doc/
/docker/
-/ee/
+/ee/bin/
+/ee/changelogs/
+/ee/config/
+/ee/db/
+/ee/fixtures/
+/ee/lib/
+/ee/locale/
+/ee/spec/
/fixtures/
/templates/
/lint/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f926cbc2939..4c7a8c05b37 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,15 @@
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"
+stages:
+ - build
+ - prepare
+ - quick-test
+ - test
+ - review
+ - qa
+ - post-test
+ - pages
+
variables:
RAILS_ENV: "test"
NODE_ENV: "test"
@@ -11,25 +21,9 @@ variables:
FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json
BUILD_ASSETS_IMAGE: "false"
-before_script:
- - date
- - source scripts/utils.sh
- - source scripts/prepare_build.sh
- - date
-
after_script:
- date
-stages:
- - build
- - prepare
- - merge
- - test
- - review
- - qa
- - post-test
- - pages
-
include:
- local: .gitlab/ci/global.gitlab-ci.yml
- local: .gitlab/ci/cng.gitlab-ci.yml
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index dae3c349ff4..0f2dd081e9e 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -9,12 +9,13 @@
app/assets/ @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter
*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter
-# Maintainers from the Database team should review changes in `db/`
-db/ @gl-database
-lib/gitlab/background_migration/ @gl-database
-lib/gitlab/database/ @gl-database
-lib/gitlab/sql/ @gl-database
-/ee/db/ @gl-database
+# Database maintainers should review changes in `db/`
+db/ @gitlab-org/maintainers/database
+lib/gitlab/background_migration/ @gitlab-org/maintainers/database
+lib/gitlab/database/ @gitlab-org/maintainers/database
+lib/gitlab/sql/ @gitlab-org/maintainers/database
+lib/gitlab/github_import/ @gitlab-org/maintainers/database
+/ee/db/ @gitlab-org/maintainers/database
# Feature specific owners
/ee/lib/gitlab/code_owners/ @reprazent
diff --git a/.gitlab/ci/cng.gitlab-ci.yml b/.gitlab/ci/cng.gitlab-ci.yml
index d624e8d09f6..a43d3694103 100644
--- a/.gitlab/ci/cng.gitlab-ci.yml
+++ b/.gitlab/ci/cng.gitlab-ci.yml
@@ -1,16 +1,15 @@
cloud-native-image:
image: ruby:2.6-alpine
- before_script: []
dependencies: []
stage: post-test
allow_failure: true
variables:
GIT_DEPTH: "1"
- cache: {}
when: manual
script:
- install_gitlab_gem
- CNG_PROJECT_PATH="gitlab-org/build/CNG" BUILD_TRIGGER_TOKEN=$CI_JOB_TOKEN ./scripts/trigger-build cng
only:
- - tags@gitlab-org/gitlab-ce
- - tags@gitlab-org/gitlab-ee
+ refs:
+ - tags@gitlab-org/gitlab-ce
+ - tags@gitlab-org/gitlab-ee
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index 39ae62a43c9..1fad731543c 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -1,24 +1,34 @@
-.review-docs: &review-docs
- extends: .single-script-job-dedicated-runner
+.review-docs:
+ extends:
+ - .default-tags
+ - .default-retry
+ image: ruby:2.6-alpine
+ stage: review
+ dependencies: []
variables:
- SCRIPT_NAME: trigger-build-docs
+ GIT_STRATEGY: none
environment:
name: review-docs/$CI_COMMIT_REF_SLUG
# DOCS_REVIEW_APPS_DOMAIN and DOCS_GITLAB_REPO_SUFFIX are CI variables
# Discussion: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14236/diffs#note_40140693
url: http://$CI_ENVIRONMENT_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
on_stop: review-docs-cleanup
+ before_script:
+ # We don't clone the repo by using GIT_STRATEGY: none and only download the
+ # single script we need here so it's much faster than cloning.
+ - apk add --update openssl
+ - wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/trigger-build-docs
+ - chmod 755 trigger-build-docs
# Trigger a manual docs build in gitlab-docs only on non docs-only branches.
# Useful to preview the docs changes live.
review-docs-deploy-manual:
extends:
- .review-docs
- - .no-docs-and-no-qa
- stage: review
+ - .except-docs-qa
script:
- gem install gitlab --no-document
- - ./$SCRIPT_NAME deploy
+ - ./trigger-build-docs deploy
when: manual
only:
- branches@gitlab-org/gitlab-ce
@@ -27,50 +37,49 @@ review-docs-deploy-manual:
# Always trigger a docs build in gitlab-docs only on docs-only branches.
# Useful to preview the docs changes live.
review-docs-deploy:
- <<: *review-docs
- stage: review
+ extends:
+ - .review-docs
+ - .except-qa
script:
- gem install gitlab --no-document
- - ./$SCRIPT_NAME deploy
+ - ./trigger-build-docs deploy
only:
- /(^docs[\/-].+|.+-docs$)/@gitlab-org/gitlab-ce
- /(^docs[\/-].+|.+-docs$)/@gitlab-org/gitlab-ee
- except:
- - /(^qa[\/-].*|.*-qa$)/
# Cleanup remote environment of gitlab-docs
review-docs-cleanup:
- <<: *review-docs
- stage: review
+ extends:
+ - .review-docs
+ - .except-qa
environment:
name: review-docs/$CI_COMMIT_REF_SLUG
action: stop
script:
- gem install gitlab --no-document
- - ./$SCRIPT_NAME cleanup
+ - ./trigger-build-docs cleanup
when: manual
only:
- branches@gitlab-org/gitlab-ce
- branches@gitlab-org/gitlab-ee
docs lint:
- extends: .dedicated-runner
+ extends:
+ - .default-tags
+ - .default-retry
+ - .except-qa
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-docs-lint"
stage: test
- cache: {}
dependencies: []
- before_script: []
script:
- scripts/lint-doc.sh
- mv doc/ /tmp/gitlab-docs/content/$DOCS_GITLAB_REPO_SUFFIX
- cd /tmp/gitlab-docs
# Lint Markdown
- - bundle exec mdl content/$DOCS_GITLAB_REPO_SUFFIX -c $CI_PROJECT_DIR/.mdlrc
+ - markdownlint --config $CI_PROJECT_DIR/.markdownlint.json content/$DOCS_GITLAB_REPO_SUFFIX/**/*.md
# Build HTML from Markdown
- bundle exec nanoc
# Check the internal links
- bundle exec nanoc check internal_links
# Check the internal anchor links
- bundle exec nanoc check internal_anchors
- except:
- - /(^qa[\/-].*|.*-qa$)/
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 5c3278fcf53..df38cb4ff8e 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -1,23 +1,19 @@
-.assets-compile-cache: &assets-compile-cache
+.assets-compile-cache:
cache:
- key: "assets-compile:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v6"
paths:
- vendor/ruby/
- .yarn-cache/
- tmp/cache/assets/sprockets
-.use-pg: &use-pg
- services:
- - name: postgres:9.6.14
- command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- - name: redis:alpine
-
.gitlab:assets:compile-metadata:
- <<: *assets-compile-cache
- extends: .dedicated-no-docs-pull-cache-job
+ extends:
+ - .default-tags
+ - .default-retry
+ - .assets-compile-cache
+ - .default-before_script
+ - .except-docs
image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-18.06.1
- dependencies:
- - setup-test-env
+ dependencies: ["setup-test-env"]
services:
- docker:19.03.0-dind
variables:
@@ -30,6 +26,14 @@
NODE_OPTIONS: --max_old_space_size=3584
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375
+ cache:
+ key: "assets-compile:production:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v6"
+ artifacts:
+ name: webpack-report
+ expire_in: 31d
+ paths:
+ - webpack-report/
+ - public/assets/
script:
- node --version
- retry yarn install --frozen-lockfile --production --cache-folder .yarn-cache --prefer-offline
@@ -42,43 +46,41 @@
- install_api_client_dependencies_with_apt
- play_job "review-build-cng" || true # this job might not exist so ignore the failure if it cannot be played
- play_job "schedule:review-build-cng" || true # this job might not exist so ignore the failure if it cannot be played
- artifacts:
- name: webpack-report
- expire_in: 31d
- paths:
- - webpack-report/
- - public/assets/
only:
- /.+/@gitlab-org/gitlab-ce
- /.+/@gitlab-org/gitlab-ee
- /.+/@gitlab/gitlabhq
- /.+/@gitlab/gitlab-ee
tags:
- - docker
- gitlab-org
+ - docker
gitlab:assets:compile:
extends: .gitlab:assets:compile-metadata
+ only:
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
cache:
policy: pull-push
- only:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
gitlab:assets:compile pull-cache:
extends: .gitlab:assets:compile-metadata
- cache:
- policy: pull
except:
refs:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- /(^docs[\/-].+|.+-docs$)/
+ cache:
+ policy: pull
.compile-assets-metadata:
- extends: .dedicated-runner
- <<: *use-pg
- <<: *assets-compile-cache
+ extends:
+ - .default-tags
+ - .default-retry
+ - .assets-compile-cache
+ - .default-before_script
+ - .use-pg
stage: prepare
script:
- node --version
@@ -89,6 +91,8 @@ gitlab:assets:compile pull-cache:
variables:
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
+ cache:
+ key: "assets-compile:test:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v6"
artifacts:
expire_in: 7d
paths:
@@ -96,30 +100,34 @@ gitlab:assets:compile pull-cache:
- public/assets
compile-assets:
- extends: .compile-assets-metadata
+ extends:
+ - .compile-assets-metadata
+ only:
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
cache:
policy: pull-push
- only:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
compile-assets pull-cache:
extends: .compile-assets-metadata
- cache:
- policy: pull
except:
refs:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- /(^docs[\/-].+|.+-docs$)/
+ cache:
+ policy: pull
karma:
- extends: .dedicated-no-docs-pull-cache-job
- <<: *use-pg
- dependencies:
- - compile-assets
- - compile-assets pull-cache
- - setup-test-env
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg
+ - .except-docs
+ dependencies: ["compile-assets", "compile-assets pull-cache", "setup-test-env"]
variables:
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
@@ -142,12 +150,14 @@ karma:
junit: junit_karma.xml
jest:
- extends: .dedicated-no-docs-and-no-qa-pull-cache-job
- <<: *use-pg
- dependencies:
- - compile-assets
- - compile-assets pull-cache
- - setup-test-env
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg
+ - .except-docs-qa
+ dependencies: ["compile-assets", "compile-assets pull-cache", "setup-test-env"]
script:
- scripts/gitaly-test-spawn
- date
@@ -170,36 +180,41 @@ jest:
- tmp/jest/jest/
policy: pull-push
-qa:internal:
- extends: .dedicated-no-docs-no-db-pull-cache-job
- services: []
- script:
+.qa:
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .except-docs
+ dependencies: ["setup-test-env"]
+ variables:
+ SETUP_DB: "false"
+ before_script:
- cd qa/
- bundle install
+
+qa:internal:
+ extends: .qa
+ script:
- bundle exec rspec
- dependencies:
- - setup-test-env
qa:selectors:
- extends: .dedicated-no-docs-no-db-pull-cache-job
- services: []
+ extends: .qa
script:
- - cd qa/
- - bundle install
- bundle exec bin/qa Test::Sanity::Selectors
- dependencies:
- - setup-test-env
-.qa-frontend-node: &qa-frontend-node
- extends: .dedicated-no-docs-no-db-pull-cache-job
- stage: test
+.qa-frontend-node:
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .except-docs
+ dependencies: []
cache:
key: "$CI_JOB_NAME"
paths:
- .yarn-cache/
policy: pull-push
- dependencies: []
- before_script: []
script:
- date
- yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline
@@ -207,23 +222,28 @@ qa:selectors:
- yarn run webpack-prod
qa-frontend-node:8:
- <<: *qa-frontend-node
+ extends: .qa-frontend-node
image: node:carbon
qa-frontend-node:10:
- <<: *qa-frontend-node
+ extends: .qa-frontend-node
image: node:dubnium
qa-frontend-node:latest:
- <<: *qa-frontend-node
+ extends: .qa-frontend-node
image: node:latest
allow_failure: true
lint:javascript:report:
- extends: .dedicated-no-docs-no-db-pull-cache-job
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .except-docs
+ variables:
+ SETUP_DB: "false"
stage: post-test
dependencies: []
- before_script: []
script:
- date
- yarn run eslint-report || true # ignore exit code
@@ -234,12 +254,15 @@ lint:javascript:report:
- eslint-report.html
jsdoc:
- extends: .dedicated-no-docs-no-db-pull-cache-job
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .except-docs
+ variables:
+ SETUP_DB: "false"
stage: post-test
- dependencies:
- - compile-assets
- - compile-assets pull-cache
- before_script: []
+ dependencies: ["compile-assets", "compile-assets pull-cache"]
script:
- date
- yarn run jsdoc || true # ignore exit code
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index 56fe9739d5f..04135447ca4 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -1,83 +1,56 @@
-.dedicated-runner:
+.default-tags:
+ tags:
+ - gitlab-org
+
+.default-retry:
retry:
max: 2 # This is confusing but this means "3 runs at max".
when:
- unknown_failure
- api_failure
- runner_system_failure
- tags:
- - gitlab-org
-
-.default-cache: &default-cache
- key: "debian-stretch-ruby-2.6.3-node-12.x"
- paths:
- - vendor/ruby
- - .yarn-cache/
- - vendor/gitaly-ruby
-.dedicated-runner-default-cache:
- extends: .dedicated-runner
- cache:
- <<: *default-cache
+.default-before_script:
+ before_script:
+ - date
+ - source scripts/utils.sh
+ - source scripts/prepare_build.sh
+ - date
# Jobs that only need to pull cache
-.dedicated-pull-cache-job:
- extends: .dedicated-runner
+.default-cache:
cache:
- <<: *default-cache
+ key: "debian-stretch-ruby-2.6.3-node-12.x"
+ paths:
+ - vendor/ruby
+ - .yarn-cache/
+ - vendor/gitaly-ruby
policy: pull
- stage: test
-.no-docs:
+.except-docs:
except:
refs:
- /(^docs[\/-].+|.+-docs$)/
-.no-docs-and-no-qa:
+.except-qa:
except:
refs:
- - /(^docs[\/-].+|.+-docs$)/
- /(^qa[\/-].*|.*-qa$)/
-.dedicated-no-docs-pull-cache-job:
- extends:
- - .dedicated-pull-cache-job
- - .no-docs
-
-.dedicated-no-docs-and-no-qa-pull-cache-job:
- extends:
- - .dedicated-pull-cache-job
- - .no-docs-and-no-qa
-
-# Jobs that do not need a DB
-.dedicated-no-docs-no-db-pull-cache-job:
- extends: .dedicated-no-docs-pull-cache-job
- variables:
- SETUP_DB: "false"
-
-# Jobs that need a dedicated runner, with no cache
-.dedicated-no-docs:
- extends:
- - .dedicated-runner
- - .no-docs
+.except-docs-qa:
+ except:
+ refs:
+ - /(^docs[\/-].+|.+-docs$)/
+ - /(^qa[\/-].*|.*-qa$)/
-.single-script-job-dedicated-runner:
- extends: .dedicated-runner
- image: ruby:2.6-alpine
- stage: test
- cache: {}
- dependencies: []
- variables:
- GIT_STRATEGY: none
- before_script:
- # We don't clone the repo by using GIT_STRATEGY: none and only download the
- # single script we need here so it's much faster than cloning.
- - export SCRIPT_NAME="${SCRIPT_NAME:-$CI_JOB_NAME}"
- - apk add --update openssl
- - wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/$SCRIPT_NAME
- - chmod 755 $(basename $SCRIPT_NAME)
+.except-docs-qa-geo:
+ except:
+ refs:
+ - /(^docs[\/-].+|.+-docs$)/
+ - /(^qa[\/-].*|.*-qa$)/
+ - /(^geo[\/-].*|.*-geo$)/
-.review-only: &review-only
+.review-only:
only:
refs:
- branches@gitlab-org/gitlab-ce
@@ -88,3 +61,16 @@
- master
- /^\d+-\d+-auto-deploy-\d+$/
- /(^docs[\/-].+|.+-docs$)/
+
+.use-pg:
+ services:
+ - name: postgres:9.6.14
+ command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
+ - name: redis:alpine
+
+.use-pg-10:
+ 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-10-graphicsmagick-1.3.33"
+ services:
+ - name: postgres:10.9
+ command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
+ - name: redis:alpine
diff --git a/.gitlab/ci/memory.gitlab-ci.yml b/.gitlab/ci/memory.gitlab-ci.yml
index 9923732e587..1936933cca4 100644
--- a/.gitlab/ci/memory.gitlab-ci.yml
+++ b/.gitlab/ci/memory.gitlab-ci.yml
@@ -1,5 +1,12 @@
memory-static:
- extends: .dedicated-no-docs-no-db-pull-cache-job
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .except-docs
+ variables:
+ SETUP_DB: "false"
script:
# Uses two different reports from the 'derailed_benchmars' gem.
@@ -23,7 +30,13 @@ memory-static:
# The application is booted in `production` environment.
# All tests are run without a webserver (directly using Rack::Mock by default).
memory-on-boot:
- extends: .rspec-metadata-pg-10
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg-10
+ - .except-docs-qa
variables:
NODE_ENV: "production"
RAILS_ENV: "production"
diff --git a/.gitlab/ci/pages.gitlab-ci.yml b/.gitlab/ci/pages.gitlab-ci.yml
index f7b18b809b4..3247d7c4bce 100644
--- a/.gitlab/ci/pages.gitlab-ci.yml
+++ b/.gitlab/ci/pages.gitlab-ci.yml
@@ -1,13 +1,15 @@
pages:
- extends: .dedicated-no-docs-no-db-pull-cache-job
- before_script: []
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .except-docs
+ only:
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
stage: pages
- dependencies:
- - coverage
- - karma
- - gitlab:assets:compile
- - lint:javascript:report
- - jsdoc
+ dependencies: ["coverage", "karma", "gitlab:assets:compile", "lint:javascript:report", "jsdoc"]
script:
- mv public/ .public/
- mkdir public/
@@ -21,6 +23,3 @@ pages:
artifacts:
paths:
- public
- only:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml
index 144e5392e55..ac2a70dda0b 100644
--- a/.gitlab/ci/qa.gitlab-ci.yml
+++ b/.gitlab/ci/qa.gitlab-ci.yml
@@ -1,9 +1,8 @@
.package-and-qa-base:
image: ruby:2.6-alpine
- stage: review # So even if review-deploy failed we can still run this
- before_script: []
+ stage: qa
+ needs: ["build-qa-image", "gitlab:assets:compile pull-cache"]
dependencies: []
- cache: {}
variables:
GIT_DEPTH: "1"
retry: 0
@@ -14,12 +13,18 @@
only:
- branches@gitlab-org/gitlab-ce
- branches@gitlab-org/gitlab-ee
+ except:
+ - master
package-and-qa-manual:
extends:
- .package-and-qa-base
- - .no-docs-and-no-qa
+ - .except-docs-qa
when: manual
+ except:
+ - master
+ - /(^docs[\/-].+|.+-docs$)/
+ - /(^qa[\/-].*|.*-qa$)
package-and-qa:
extends: .package-and-qa-base
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 50476b43dd6..2e8b197829b 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -1,52 +1,31 @@
-.use-pg: &use-pg
- services:
- - name: postgres:9.6.14
- command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- - name: redis:alpine
-
-.use-pg-10: &use-pg-10
- services:
- - name: postgres:10.9
- command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- - name: redis:alpine
-
-.only-schedules-master: &only-schedules-master
+.only-schedules-master:
only:
- - schedules@gitlab-org/gitlab-ce
- - schedules@gitlab-org/gitlab-ee
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
- - master@gitlab/gitlabhq
- - master@gitlab/gitlab-ee
+ refs:
+ - schedules@gitlab-org/gitlab-ce
+ - schedules@gitlab-org/gitlab-ee
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
+ - master@gitlab/gitlabhq
+ - master@gitlab/gitlab-ee
-.gitlab-setup: &gitlab-setup
+.rake-exec:
extends:
- - .dedicated-no-docs-and-no-qa-pull-cache-job
- - .use-pg
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
variables:
SETUP_DB: "false"
script:
- # Manually clone gitlab-test and only seed this project in
- # db/fixtures/development/04_project.rb thanks to SIZE=1 below
- - git clone https://gitlab.com/gitlab-org/gitlab-test.git
- /home/git/repositories/gitlab-org/gitlab-test.git
- - scripts/gitaly-test-spawn
- - force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup
- artifacts:
- when: on_failure
- expire_in: 1d
- paths:
- - log/development.log
-
-.rake-exec: &rake-exec
- extends: .dedicated-no-docs-no-db-pull-cache-job
- script:
- bundle exec rake $CI_JOB_NAME
-.rspec-metadata: &rspec-metadata
+.rspec-base:
extends:
- - .dedicated-pull-cache-job
- - .no-docs-and-no-qa
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .except-docs-qa
stage: test
script:
- JOB_NAME=( $CI_JOB_NAME )
@@ -83,52 +62,24 @@
reports:
junit: junit_rspec.xml
-.rspec-metadata-pg: &rspec-metadata-pg
- <<: *rspec-metadata
- <<: *use-pg
-
-.rspec-metadata-pg-10: &rspec-metadata-pg-10
- <<: *rspec-metadata
- <<: *use-pg-10
- 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-10-graphicsmagick-1.3.33"
-
-# DB migration, rollback, and seed jobs
-.db-migrate-reset: &db-migrate-reset
- extends: .dedicated-no-docs-and-no-qa-pull-cache-job
- script:
- - bundle exec rake db:migrate:reset
- dependencies:
- - setup-test-env
+.rspec-base-pg:
+ extends:
+ - .rspec-base
+ - .use-pg
-.migration-paths: &migration-paths
- extends: .dedicated-no-docs-and-no-qa-pull-cache-job
- variables:
- SETUP_DB: "false"
- script:
- - git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v11.11.0
- - git checkout -f FETCH_HEAD
- - sed -i "s/gem 'oj', '~> 2.17.4'//" Gemfile
- - sed -i "s/gem 'bootsnap', '~> 1.0.0'/gem 'bootsnap'/" Gemfile
- - bundle update google-protobuf grpc bootsnap
- - bundle install $BUNDLE_INSTALL_FLAGS
- - date
- - cp config/gitlab.yml.example config/gitlab.yml
- - bundle exec rake db:drop db:create db:schema:load db:seed_fu
- - date
- - git checkout -f $CI_COMMIT_SHA
- - bundle install $BUNDLE_INSTALL_FLAGS
- - date
- - . scripts/prepare_build.sh
- - date
- - bundle exec rake db:migrate
- dependencies:
- - setup-test-env
+.rspec-base-pg-10:
+ extends:
+ - .rspec-base
+ - .use-pg-10
setup-test-env:
extends:
- - .dedicated-runner-default-cache
- - .no-docs
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
- .use-pg
+ - .except-docs
stage: prepare
script:
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
@@ -141,67 +92,72 @@ setup-test-env:
- vendor/gitaly-ruby
rspec unit pg:
- <<: *rspec-metadata-pg
+ extends: .rspec-base-pg
parallel: 20
rspec integration pg:
- <<: *rspec-metadata-pg
+ extends: .rspec-base-pg
parallel: 6
rspec system pg:
- <<: *rspec-metadata-pg
+ extends: .rspec-base-pg
parallel: 24
rspec unit pg-10:
- <<: *rspec-metadata-pg-10
- <<: *only-schedules-master
+ extends:
+ - .rspec-base-pg-10
+ - .only-schedules-master
parallel: 20
rspec integration pg-10:
- <<: *rspec-metadata-pg-10
- <<: *only-schedules-master
+ extends:
+ - .rspec-base-pg-10
+ - .only-schedules-master
parallel: 6
rspec system pg-10:
- <<: *rspec-metadata-pg-10
- <<: *only-schedules-master
+ extends:
+ - .rspec-base-pg-10
+ - .only-schedules-master
parallel: 24
rspec-fast-spec-helper:
- <<: *rspec-metadata-pg
+ extends: .rspec-base-pg
script:
- bundle exec rspec spec/fast_spec_helper.rb
-.rspec-quarantine: &rspec-quarantine
- <<: *only-schedules-master
+rspec quarantine pg:
+ extends:
+ - .default-before_script
+ - .rspec-base-pg
+ - .only-schedules-master
script:
- - export CACHE_CLASSES=true
+ - export NO_KNAPSACK=1 CACHE_CLASSES=true
- scripts/gitaly-test-spawn
- bin/rspec --color --format documentation --tag quarantine -- spec/
-
-rspec quarantine pg:
- <<: *rspec-metadata-pg
- <<: *rspec-quarantine
allow_failure: true
static-analysis:
- extends: .dedicated-no-docs-no-db-pull-cache-job
- dependencies:
- - compile-assets
- - compile-assets pull-cache
- - setup-test-env
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .except-docs
+ dependencies: ["setup-test-env", "compile-assets", "compile-assets pull-cache"]
+ variables:
+ SETUP_DB: "false"
script:
- scripts/static-analysis
cache:
- key: "debian-stretch-ruby-2.6.3-node-12.x-and-rubocop"
+ key: "debian-stretch-ruby-2.6.3-and-rubocop"
paths:
- vendor/ruby
- - .yarn-cache/
- tmp/rubocop_cache
policy: pull-push
downtime_check:
- <<: *rake-exec
+ extends: .rake-exec
except:
refs:
- master
@@ -209,22 +165,20 @@ downtime_check:
- /^[\d-]+-stable(-ee)?$/
- /(^docs[\/-].+|.+-docs$)/
- /(^qa[\/-].*|.*-qa$)/
- dependencies:
- - setup-test-env
+ dependencies: ["setup-test-env"]
ee_compat_check:
- <<: *rake-exec
+ extends: .rake-exec
dependencies: []
except:
refs:
- master
- tags
- - /[\d-]+-stable(-ee)?/
- - /^security-/
- branches@gitlab-org/gitlab-ee
- branches@gitlab/gitlab-ee
+ - /^[\d-]+-stable(-ee)?$/
- /(^docs[\/-].+|.+-docs$)/
- retry: 0
+ - /^security-/
artifacts:
name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}"
when: always
@@ -232,44 +186,106 @@ ee_compat_check:
paths:
- ee_compat_check/patches/*.patch
-db:migrate:reset-pg:
- <<: *db-migrate-reset
- <<: *use-pg
+# DB migration, rollback, and seed jobs
+db:migrate:reset:
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg
+ - .except-docs-qa
+ dependencies: ["setup-test-env"]
+ script:
+ - bundle exec rake db:migrate:reset
-db:check-schema-pg:
- <<: *db-migrate-reset
- <<: *use-pg
+db:check-schema:
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg
+ - .except-docs-qa
+ dependencies: ["setup-test-env"]
script:
- source scripts/schema_changed.sh
-migration:path-pg:
- <<: *migration-paths
- <<: *use-pg
+db:migrate-from-v11.11.0:
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg
+ - .except-docs-qa
+ dependencies: ["setup-test-env"]
+ variables:
+ SETUP_DB: "false"
+ script:
+ - git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v11.11.0
+ - git checkout -f FETCH_HEAD
+ - sed -i "s/gem 'oj', '~> 2.17.4'//" Gemfile
+ - sed -i "s/gem 'bootsnap', '~> 1.0.0'/gem 'bootsnap'/" Gemfile
+ - bundle update google-protobuf grpc bootsnap
+ - bundle install $BUNDLE_INSTALL_FLAGS
+ - date
+ - cp config/gitlab.yml.example config/gitlab.yml
+ - bundle exec rake db:drop db:create db:schema:load db:seed_fu
+ - date
+ - git checkout -f $CI_COMMIT_SHA
+ - bundle install $BUNDLE_INSTALL_FLAGS
+ - date
+ - . scripts/prepare_build.sh
+ - date
+ - bundle exec rake db:migrate
-.db-rollback: &db-rollback
- extends: .dedicated-no-docs-and-no-qa-pull-cache-job
+db:rollback:
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg
+ - .except-docs-qa
+ dependencies: ["setup-test-env"]
script:
- bundle exec rake db:migrate VERSION=20180101160629
- bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true
- dependencies:
- - setup-test-env
-
-db:rollback-pg:
- <<: *db-rollback
- <<: *use-pg
-gitlab:setup-pg:
- <<: *gitlab-setup
- <<: *use-pg
- dependencies:
- - setup-test-env
+gitlab:setup:
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .use-pg
+ - .except-docs-qa
+ dependencies: ["setup-test-env"]
+ variables:
+ SETUP_DB: "false"
+ script:
+ # Manually clone gitlab-test and only seed this project in
+ # db/fixtures/development/04_project.rb thanks to SIZE=1 below
+ - git clone https://gitlab.com/gitlab-org/gitlab-test.git
+ /home/git/repositories/gitlab-org/gitlab-test.git
+ - scripts/gitaly-test-spawn
+ - force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup
+ artifacts:
+ when: on_failure
+ expire_in: 1d
+ paths:
+ - log/development.log
coverage:
# Don't include dedicated-no-docs-no-db-pull-cache-job here since we need to
# download artifacts from all the rspec jobs instead of from setup-test-env only
extends:
- - .dedicated-runner-default-cache
- - .no-docs-and-no-qa
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .except-docs-qa
cache:
policy: pull
variables:
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index ccd7d6ec84d..905f1ede2c4 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -4,35 +4,29 @@ include:
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Security/DAST.gitlab-ci.yml
+.reports:
+ extends:
+ - .default-retry
+ - .except-docs
+ tags:
+ - gitlab-org
+ - docker
+
code_quality:
- extends: .dedicated-no-docs
- # gitlab-org runners set `privileged: false` but we need to have it set to true
- # since we're using Docker in Docker
- tags: []
- before_script: []
- cache: {}
+ extends: .reports
sast:
- extends: .dedicated-no-docs
- tags: []
- before_script: []
- cache: {}
+ extends: .reports
variables:
SAST_BRAKEMAN_LEVEL: 2
+ SAST_EXCLUDED_PATHS: qa,spec,doc
dependency_scanning:
- extends: .dedicated-no-docs
- tags: []
- before_script: []
- cache: {}
+ extends: .reports
dast:
- extends:
- - .dedicated-runner
- - .review-only
+ extends: .reports
stage: qa
- dependencies:
- - review-deploy
+ dependencies: ["review-deploy"]
before_script:
- export DAST_WEBSITE="$(cat review_app_url.txt)"
- cache: {}
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index beb049c0b3b..3415f1b6ab4 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -1,4 +1,4 @@
-.review-schedules-only: &review-schedules-only
+.review-schedules-only:
only:
refs:
- schedules@gitlab-org/gitlab-ce
@@ -11,39 +11,39 @@
- tags
- /(^docs[\/-].+|.+-docs$)/
-.review-base: &review-base
+.review-base:
extends:
- - .dedicated-runner
+ - .default-tags
+ - .default-retry
- .review-only
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
- cache: {}
dependencies: []
before_script:
- source scripts/utils.sh
-.review-docker: &review-docker
- <<: *review-base
+.review-docker:
+ extends: .review-base
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine
services:
- docker:19.03.0-dind
tags:
- gitlab-org
- docker
- variables: &review-docker-variables
+ variables:
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375
LATEST_QA_IMAGE: "gitlab/${CI_PROJECT_NAME}-qa:nightly"
QA_IMAGE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab/${CI_PROJECT_NAME}-qa:${CI_COMMIT_REF_SLUG}"
build-qa-image:
- <<: *review-docker
+ extends: .review-docker
stage: test
script:
- time docker build --cache-from ${LATEST_QA_IMAGE} --tag ${QA_IMAGE} --file ./qa/Dockerfile ./
- echo "${CI_JOB_TOKEN}" | docker login --username gitlab-ci-token --password-stdin ${CI_REGISTRY}
- time docker push ${QA_IMAGE}
-.review-build-cng-base: &review-build-cng-base
+.review-build-cng-base:
image: ruby:2.6-alpine
stage: test
when: manual
@@ -52,20 +52,21 @@ build-qa-image:
- install_api_client_dependencies_with_apk
- install_gitlab_gem
dependencies: []
- cache: {}
script:
- BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./scripts/trigger-build cng
review-build-cng:
- extends: .review-only
- <<: *review-build-cng-base
+ extends:
+ - .review-build-cng-base
+ - .review-only
schedule:review-build-cng:
- <<: *review-schedules-only
- <<: *review-build-cng-base
+ extends:
+ - .review-build-cng-base
+ - .review-schedules-only
-.review-deploy-base: &review-deploy-base
- <<: *review-base
+review-deploy:
+ extends: .review-base
allow_failure: true
retry: 1
stage: review
@@ -73,7 +74,7 @@ schedule:review-build-cng:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
GITLAB_HELM_CHART_REF: "master"
- environment: &review-environment
+ environment:
name: review/${CI_COMMIT_REF_NAME}
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
on_stop: review-stop
@@ -98,50 +99,45 @@ schedule:review-build-cng:
expire_in: 2 days
when: always
-review-deploy:
- <<: *review-deploy-base
-
schedule:review-deploy:
- <<: *review-deploy-base
- <<: *review-schedules-only
+ extends:
+ - review-deploy
+ - .review-schedules-only
review-stop:
- extends:
- - .single-script-job-dedicated-runner
- - .review-only
- image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
- stage: review
+ extends: review-deploy
when: manual
- allow_failure: true
- variables:
- SCRIPT_NAME: review_apps/review-apps.sh
environment:
- <<: *review-environment
action: stop
- script:
+ variables:
+ GIT_STRATEGY: none
+ before_script:
+ # We don't clone the repo by using GIT_STRATEGY: none and only download the
+ # single script we need here so it's much faster than cloning.
+ - apk add --update openssl
+ - wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/review_apps/review-apps.sh
- wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/utils.sh
- source utils.sh
- - source $(basename $SCRIPT_NAME)
+ - source review-apps.sh
+ script:
- delete
+ artifacts: {}
-.review-qa-base: &review-qa-base
- <<: *review-docker
- allow_failure: true
+.review-qa-base:
+ extends: .review-docker
retry: 2
stage: qa
variables:
- <<: *review-docker-variables
QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa"
QA_CAN_TEST_GIT_PROTOCOL_V2: "false"
+ QA_DEBUG: "true"
GITLAB_USERNAME: "root"
GITLAB_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}"
GITLAB_ADMIN_USERNAME: "root"
GITLAB_ADMIN_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}"
GITHUB_ACCESS_TOKEN: "${REVIEW_APPS_QA_GITHUB_ACCESS_TOKEN}"
EE_LICENSE: "${REVIEW_APPS_EE_LICENSE}"
- QA_DEBUG: "true"
- dependencies:
- - review-deploy
+ dependencies: ["review-deploy"]
artifacts:
paths:
- ./qa/gitlab-qa-run-*
@@ -156,12 +152,13 @@ review-stop:
- gem install gitlab-qa --no-document ${GITLAB_QA_VERSION:+ --version ${GITLAB_QA_VERSION}}
review-qa-smoke:
- <<: *review-qa-base
+ extends: .review-qa-base
+ allow_failure: true
script:
- gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
review-qa-all:
- <<: *review-qa-base
+ extends: .review-qa-base
allow_failure: true
when: manual
parallel: 5
@@ -172,21 +169,16 @@ review-qa-all:
parallel-spec-reports:
extends:
- - .dedicated-runner
- - .no-docs
- dependencies:
- - review-qa-all
+ - .default-tags
+ - .except-docs
image: ruby:2.6-alpine
- services: []
- before_script: []
+ stage: post-test
+ dependencies: ["review-qa-all"]
variables:
- SETUP_DB: "false"
NEW_PARALLEL_SPECS_REPORT: qa/report-new.html
BASE_ARTIFACT_URL: "${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/file/qa/"
- stage: post-test
allow_failure: true
when: manual
- retry: 0
artifacts:
when: always
paths:
@@ -196,15 +188,15 @@ parallel-spec-reports:
junit: qa/gitlab-qa-run-*/**/rspec-*.xml
script:
- apk add --update build-base libxml2-dev libxslt-dev && rm -rf /var/cache/apk/*
- - gem install nokogiri
+ - gem install nokogiri --no-document
- cd qa/gitlab-qa-run-*/gitlab-*
- ARTIFACT_DIRS=$(pwd |rev| awk -F / '{print $1,$2}' | rev | sed s_\ _/_)
- - cd ../../..
+ - cd -
- '[[ -f $NEW_PARALLEL_SPECS_REPORT ]] || echo "{}" > ${NEW_PARALLEL_SPECS_REPORT}'
- scripts/merge-html-reports ${NEW_PARALLEL_SPECS_REPORT} ${BASE_ARTIFACT_URL}${ARTIFACT_DIRS} qa/gitlab-qa-run-*/**/rspec.htm
-.review-performance-base: &review-performance-base
- <<: *review-qa-base
+review-performance:
+ extends: .review-qa-base
allow_failure: true
before_script:
- export CI_ENVIRONMENT_URL="$(cat review_app_url.txt)"
@@ -222,18 +214,16 @@ parallel-spec-reports:
reports:
performance: performance.json
-review-performance:
- <<: *review-performance-base
-
schedule:review-performance:
- <<: *review-performance-base
- <<: *review-schedules-only
- dependencies:
- - schedule:review-deploy
+ extends:
+ - review-performance
+ - .review-schedules-only
+ dependencies: ["schedule:review-deploy"]
schedule:review-cleanup:
- <<: *review-base
- <<: *review-schedules-only
+ extends:
+ - .review-base
+ - .review-schedules-only
stage: build
allow_failure: true
environment:
@@ -246,11 +236,13 @@ schedule:review-cleanup:
- ruby -rrubygems scripts/review_apps/automated_cleanup.rb
danger-review:
- extends: .dedicated-pull-cache-job
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
image: registry.gitlab.com/gitlab-org/gitlab-build-images:danger
stage: test
dependencies: []
- before_script: []
only:
variables:
- $DANGER_GITLAB_API_TOKEN
@@ -259,9 +251,8 @@ danger-review:
- master
- /^\d+-\d+-auto-deploy-\d+$/
- /^[\d-]+-stable(-ee)?$/
- variables:
- - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/
- - $CI_COMMIT_REF_NAME =~ /.*-stable(-ee)?-prepare-.*/
+ - /^ce-to-ee-.*/
+ - /.*-stable(-ee)?-prepare-.*/
script:
- git version
- node --version
diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml
index c1fc3a893ca..d9384780356 100644
--- a/.gitlab/ci/setup.gitlab-ci.yml
+++ b/.gitlab/ci/setup.gitlab-ci.yml
@@ -1,41 +1,42 @@
# Insurance in case a gem needed by one of our releases gets yanked from
# rubygems.org in the future.
cache gems:
- extends: .dedicated-no-docs-no-db-pull-cache-job
+ extends:
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
+ - .except-docs
+ dependencies: ["setup-test-env"]
+ variables:
+ SETUP_DB: "false"
script:
- bundle package --all --all-platforms
artifacts:
paths:
- vendor/cache
only:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
- - tags
- dependencies:
- - setup-test-env
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
+ - tags
-gitlab_git_test:
+.minimal-job:
extends:
- - .dedicated-runner
- - .no-docs-and-no-qa
- variables:
- SETUP_DB: "false"
- before_script: []
+ - .default-tags
+ - .default-retry
+ - .except-docs-qa
dependencies: []
- cache: {}
+
+gitlab_git_test:
+ extends: .minimal-job
script:
- spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
no_ee_check:
- extends:
- - .dedicated-runner
- - .no-docs-and-no-qa
- variables:
- SETUP_DB: "false"
- before_script: []
- dependencies: []
- cache: {}
+ extends: .minimal-job
script:
- scripts/no-ee-check
only:
- - /.+/@gitlab-org/gitlab-ce
+ refs:
+ - branches@gitlab-org/gitlab-ce
diff --git a/.gitlab/ci/test-metadata.gitlab-ci.yml b/.gitlab/ci/test-metadata.gitlab-ci.yml
index 4c97a4feb18..b9dac64957e 100644
--- a/.gitlab/ci/test-metadata.gitlab-ci.yml
+++ b/.gitlab/ci/test-metadata.gitlab-ci.yml
@@ -1,5 +1,4 @@
-.tests-metadata-state: &tests-metadata-state
- extends: .dedicated-runner
+.tests-metadata-state:
variables:
TESTS_METADATA_S3_BUCKET: "gitlab-ce-cache"
before_script:
@@ -14,7 +13,7 @@
retrieve-tests-metadata:
extends:
- .tests-metadata-state
- - .no-docs-and-no-qa
+ - .except-docs-qa
stage: prepare
cache:
key: tests_metadata
@@ -29,7 +28,7 @@ retrieve-tests-metadata:
- '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}'
update-tests-metadata:
- <<: *tests-metadata-state
+ extends: .tests-metadata-state
stage: post-test
cache:
key: tests_metadata
@@ -49,25 +48,24 @@ update-tests-metadata:
- rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json
- scripts/insert-rspec-profiling-data
only:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
- - master@gitlab/gitlabhq
- - master@gitlab/gitlab-ee
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
+ - master@gitlab/gitlabhq
+ - master@gitlab/gitlab-ee
flaky-examples-check:
- extends: .dedicated-runner
+ extends:
+ - .default-tags
+ - .default-retry
image: ruby:2.6-alpine
- services: []
- before_script: []
+ stage: post-test
variables:
- SETUP_DB: "false"
- USE_BUNDLE_INSTALL: "false"
NEW_FLAKY_SPECS_REPORT: rspec_flaky/report-new.json
- stage: post-test
allow_failure: true
- retry: 0
only:
- - branches
+ refs:
+ - branches
except:
refs:
- master
diff --git a/.gitlab/ci/yaml.gitlab-ci.yml b/.gitlab/ci/yaml.gitlab-ci.yml
index b7aa418d8f7..3e107b475c9 100644
--- a/.gitlab/ci/yaml.gitlab-ci.yml
+++ b/.gitlab/ci/yaml.gitlab-ci.yml
@@ -1,9 +1,10 @@
# Yamllint of *.yml for .gitlab-ci.yml.
# This uses rules from project root `.yamllint`.
lint-ci-gitlab:
- extends: .dedicated-runner
- before_script: []
- dependencies: []
+ extends:
+ - .default-tags
+ - .default-retry
image: sdesbure/yamllint:latest
+ dependencies: []
script:
- yamllint .gitlab-ci.yml .gitlab/ci lib/gitlab/ci/templates changelogs
diff --git a/.markdownlint.json b/.markdownlint.json
new file mode 100644
index 00000000000..2c40c0859f0
--- /dev/null
+++ b/.markdownlint.json
@@ -0,0 +1,31 @@
+{
+ "default": true,
+ "first-header-h1": true,
+ "header-style": {
+ "style": "atx"
+ },
+ "ul-style": {
+ "style": "dash"
+ },
+ "line-length": false,
+ "commands-show-output": false,
+ "no-duplicate-header": {
+ "allow_different_nesting": true
+ },
+ "no-trailing-punctuation": {
+ "punctuation": ".,;:!。,;:!?"
+ },
+ "ol-prefix": {
+ "style": "one"
+ },
+ "no-inline-html": false,
+ "hr-style": {
+ "style": "---"
+ },
+ "no-emphasis-as-heading": false,
+ "fenced-code-language": false,
+ "first-line-h1": false,
+ "code-block-style": {
+ "style": "fenced"
+ }
+}
diff --git a/.mdlrc b/.mdlrc
deleted file mode 100644
index 151c54f7d44..00000000000
--- a/.mdlrc
+++ /dev/null
@@ -1,7 +0,0 @@
-# This is the options file for mdl, configured in .gitlab/ci/docs.gitlab-ci.yml,
-# and related to the style file ./mdlrc.style
-
-# See https://github.com/markdownlint/markdownlint/blob/master/docs/configuration.md
-
-ignore_front_matter true
-style File.expand_path('.mdlrc.style', __dir__)
diff --git a/.mdlrc.style b/.mdlrc.style
deleted file mode 100644
index 85bc3aaa99b..00000000000
--- a/.mdlrc.style
+++ /dev/null
@@ -1,32 +0,0 @@
-# This is the style file for mdl, configured in .gitlab/ci/docs.gitlab-ci.yml,
-# and related to the options file ./mdlrc
-
-# See https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md
-# for more detailed information on the rules and styles.
-
-rule "MD001"
-rule "MD002"
-rule "MD003", :style => :atx
-rule "MD006"
-rule "MD010"
-rule "MD011"
-rule "MD012"
-rule "MD019"
-rule "MD022"
-rule "MD023"
-rule "MD025"
-rule "MD028"
-rule "MD029", :style => :one
-rule "MD030"
-# rule "MD032"
-rule "MD034"
-rule "MD037"
-rule "MD038"
-
-# Should not be used currently:
-
-# rule "MD004", :style => :dash # unordered list style - dash
-# False positives, see https://github.com/markdownlint/markdownlint/issues/261
-
-# rule "MD039" # Spaces inside link text
-# Crashes when link text has certain punctuation
diff --git a/.rubocop.yml b/.rubocop.yml
index b75c63e1f58..012f4890c33 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -178,6 +178,9 @@ Gitlab/ModuleWithInstanceVariables:
Gitlab/HTTParty:
Enabled: true
+ Exclude:
+ - 'spec/**/*'
+ - 'ee/spec/**/*'
GitlabSecurity/PublicSend:
Enabled: true
@@ -211,3 +214,54 @@ ActiveRecordAssociationReload:
Exclude:
- 'spec/**/*'
- 'ee/spec/**/*'
+
+RSpec/FactoriesInMigrationSpecs:
+ Enabled: true
+ Include:
+ - 'spec/migrations/**/*.rb'
+ - 'ee/spec/migrations/**/*.rb'
+ - 'spec/lib/gitlab/background_migration/**/*.rb'
+ - 'ee/spec/lib/gitlab/background_migration/**/*.rb'
+
+Cop/IncludeActionViewContext:
+ Enabled: true
+ Exclude:
+ - 'spec/**/*'
+ - 'ee/spec/**/*'
+
+Cop/IncludeSidekiqWorker:
+ Enabled: true
+ Exclude:
+ - 'spec/**/*'
+ - 'ee/spec/**/*'
+
+Gitlab/Union:
+ Enabled: true
+ Exclude:
+ - 'spec/**/*'
+ - 'ee/spec/**/*'
+
+Cop/SidekiqOptionsQueue:
+ Enabled: true
+ Exclude:
+ - 'spec/**/*.rb'
+ - 'ee/spec/**/*.rb'
+
+Graphql/AuthorizeTypes:
+ Enabled: true
+ Exclude:
+ - 'spec/**/*.rb'
+ - 'ee/spec/**/*.rb'
+
+RSpec/EnvAssignment:
+ Enable: true
+ Include:
+ - 'spec/**/*.rb'
+ - 'ee/spec/**/*.rb'
+ 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'
diff --git a/Gemfile b/Gemfile
index e5023a6f67d..595dedd4656 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.0'
+gem 'graphql', '= 1.8.4'
gem 'graphiql-rails', '~> 1.4.10'
gem 'apollo_upload_server', '~> 2.0.0.beta3'
gem 'graphql-docs', '~> 1.6.0', group: [:development, :test]
@@ -399,7 +399,7 @@ gem 'mail_room', '~> 0.9.1'
gem 'email_reply_trimmer', '~> 0.1'
gem 'html2text'
-gem 'ruby-prof', '~> 0.17.0'
+gem 'ruby-prof', '~> 1.0.0'
gem 'rbtrace', '~> 0.4', require: false
gem 'memory_profiler', '~> 0.9', require: false
gem 'benchmark-memory', '~> 0.1', require: false
@@ -438,6 +438,7 @@ gem 'toml-rb', '~> 1.0.0', require: false
gem 'flipper', '~> 0.13.0'
gem 'flipper-active_record', '~> 0.13.0'
gem 'flipper-active_support_cache_store', '~> 0.13.0'
+gem 'unleash', '~> 0.1.5'
# Structured logging
gem 'lograge', '~> 0.5'
diff --git a/Gemfile.lock b/Gemfile.lock
index d9a32027f3c..ae0d0e78c37 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -375,7 +375,7 @@ GEM
graphiql-rails (1.4.10)
railties
sprockets-rails
- graphql (1.8.1)
+ graphql (1.8.4)
graphql-docs (1.6.0)
commonmarker (~> 0.16)
escape_utils (~> 1.2)
@@ -535,6 +535,7 @@ GEM
multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
+ murmurhash3 (0.1.6)
mustermann (1.0.3)
mustermann-grape (1.0.0)
mustermann (~> 1.0.0)
@@ -836,7 +837,7 @@ GEM
i18n
ruby-fogbugz (0.2.1)
crack (~> 0.4)
- ruby-prof (0.17.0)
+ ruby-prof (1.0.0)
ruby-progressbar (1.10.1)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
@@ -972,6 +973,8 @@ GEM
get_process_mem (~> 0)
unicorn (>= 4, < 6)
uniform_notifier (1.10.0)
+ unleash (0.1.5)
+ murmurhash3 (~> 0.1.6)
unparser (0.4.5)
abstract_type (~> 0.0.7)
adamantium (~> 0.2.0)
@@ -1115,7 +1118,7 @@ DEPENDENCIES
grape-path-helpers (~> 1.1)
grape_logging (~> 1.7)
graphiql-rails (~> 1.4.10)
- graphql (~> 1.8.0)
+ graphql (= 1.8.4)
graphql-docs (~> 1.6.0)
grpc (~> 1.19.0)
haml_lint (~> 0.31.0)
@@ -1215,7 +1218,7 @@ DEPENDENCIES
rubocop-performance (~> 1.1.0)
rubocop-rspec (~> 1.22.1)
ruby-fogbugz (~> 0.2.1)
- ruby-prof (~> 0.17.0)
+ ruby-prof (~> 1.0.0)
ruby-progressbar
ruby_parser (~> 3.8)
rubyzip (~> 1.2.2)
@@ -1251,6 +1254,7 @@ DEPENDENCIES
unf (~> 0.1.4)
unicorn (~> 5.4.1)
unicorn-worker-killer (~> 0.4.4)
+ unleash (~> 0.1.5)
validates_hostname (~> 1.0.6)
version_sorter (~> 2.2.4)
vmstat (~> 2.3.0)
diff --git a/app/assets/javascripts/lib/utils/http_status.js b/app/assets/javascripts/lib/utils/http_status.js
index 37ad1676f7a..5e5d10883a3 100644
--- a/app/assets/javascripts/lib/utils/http_status.js
+++ b/app/assets/javascripts/lib/utils/http_status.js
@@ -19,6 +19,7 @@ const httpStatusCodes = {
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
+ GONE: 410,
UNPROCESSABLE_ENTITY: 422,
};
diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue
index 2fdc75f63ca..02e7a7ba0a6 100644
--- a/app/assets/javascripts/monitoring/components/charts/time_series.vue
+++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue
@@ -48,6 +48,11 @@ export default {
required: false,
default: false,
},
+ singleEmbed: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
thresholds: {
type: Array,
required: false,
@@ -267,7 +272,10 @@ export default {
</script>
<template>
- <div class="prometheus-graph col-12 col-lg-6" :class="[showBorder ? 'p-2' : 'p-0']">
+ <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 class="prometheus-graph-title js-graph-title">{{ graphData.title }}</h5>
diff --git a/app/assets/javascripts/monitoring/components/embed.vue b/app/assets/javascripts/monitoring/components/embed.vue
index e3256147618..b516a82c170 100644
--- a/app/assets/javascripts/monitoring/components/embed.vue
+++ b/app/assets/javascripts/monitoring/components/embed.vue
@@ -2,7 +2,7 @@
import { mapActions, mapState } from 'vuex';
import { getParameterValues, removeParams } from '~/lib/utils/url_utility';
import GraphGroup from './graph_group.vue';
-import MonitorAreaChart from './charts/area.vue';
+import MonitorTimeSeriesChart from './charts/time_series.vue';
import { sidebarAnimationDuration } from '../constants';
import { getTimeDiff } from '../utils';
@@ -11,7 +11,7 @@ let sidebarMutationObserver;
export default {
components: {
GraphGroup,
- MonitorAreaChart,
+ MonitorTimeSeriesChart,
},
props: {
dashboardUrl: {
@@ -92,7 +92,7 @@ export default {
<template>
<div class="metrics-embed" :class="{ 'd-inline-flex col-lg-6 p-0': isSingleChart }">
<div v-if="charts.length" class="row w-100 m-n2 pb-4">
- <monitor-area-chart
+ <monitor-time-series-chart
v-for="graphData in charts"
:key="graphData.title"
:graph-data="graphData"
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index 96f62bc85ee..73ff651d510 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -10,14 +10,14 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
-import MonitorAreaChart from './charts/area.vue';
+import MonitorTimeSeriesChart from './charts/time_series.vue';
import MonitorSingleStatChart from './charts/single_stat.vue';
import MonitorEmptyChart from './charts/empty_chart.vue';
export default {
components: {
- MonitorAreaChart,
MonitorSingleStatChart,
+ MonitorTimeSeriesChart,
MonitorEmptyChart,
Icon,
GlDropdown,
@@ -92,7 +92,7 @@ export default {
v-if="isPanelType('single-stat') && graphDataHasMetrics"
:graph-data="graphData"
/>
- <monitor-area-chart
+ <monitor-time-series-chart
v-else-if="graphDataHasMetrics"
:graph-data="graphData"
:deployment-data="deploymentData"
@@ -136,6 +136,6 @@ export default {
</gl-dropdown-item>
</gl-dropdown>
</div>
- </monitor-area-chart>
+ </monitor-time-series-chart>
<monitor-empty-chart v-else :graph-title="graphData.title" />
</template>
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index 2f201839d45..9019f0542b6 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -14,6 +14,7 @@ import NoteBody from './note_body.vue';
import eventHub from '../event_hub';
import noteable from '../mixins/noteable';
import resolvable from '../mixins/resolvable';
+import httpStatusCodes from '~/lib/utils/http_status';
export default {
name: 'NoteableNote',
@@ -122,7 +123,13 @@ export default {
},
methods: {
- ...mapActions(['deleteNote', 'updateNote', 'toggleResolveNote', 'scrollToNoteIfNeeded']),
+ ...mapActions([
+ 'deleteNote',
+ 'removeNote',
+ 'updateNote',
+ 'toggleResolveNote',
+ 'scrollToNoteIfNeeded',
+ ]),
editHandler() {
this.isEditing = true;
this.$emit('handleEdit');
@@ -185,15 +192,21 @@ export default {
this.updateSuccess();
callback();
})
- .catch(() => {
- this.isRequesting = false;
- this.isEditing = true;
- this.$nextTick(() => {
- const msg = __('Something went wrong while editing your comment. Please try again.');
- Flash(msg, 'alert', this.$el);
- this.recoverNoteContent(noteText);
+ .catch(response => {
+ if (response.status === httpStatusCodes.GONE) {
+ this.removeNote(this.note);
+ this.updateSuccess();
callback();
- });
+ } else {
+ this.isRequesting = false;
+ this.isEditing = true;
+ this.$nextTick(() => {
+ const msg = __('Something went wrong while editing your comment. Please try again.');
+ Flash(msg, 'alert', this.$el);
+ this.recoverNoteContent(noteText);
+ callback();
+ });
+ }
});
},
formCancelHandler(shouldConfirm, isDirty) {
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index b7857997d42..411bd585672 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -61,18 +61,22 @@ export const updateDiscussion = ({ commit, state }, discussion) => {
return utils.findNoteObjectById(state.discussions, discussion.id);
};
-export const deleteNote = ({ commit, dispatch, state }, note) =>
- axios.delete(note.path).then(() => {
- const discussion = state.discussions.find(({ id }) => id === note.discussion_id);
+export const removeNote = ({ commit, dispatch, state }, note) => {
+ const discussion = state.discussions.find(({ id }) => id === note.discussion_id);
- commit(types.DELETE_NOTE, note);
+ commit(types.DELETE_NOTE, note);
- dispatch('updateMergeRequestWidget');
- dispatch('updateResolvableDiscussionsCounts');
+ dispatch('updateMergeRequestWidget');
+ dispatch('updateResolvableDiscussionsCounts');
- if (isInMRPage()) {
- dispatch('diffs/removeDiscussionsFromDiff', discussion);
- }
+ if (isInMRPage()) {
+ dispatch('diffs/removeDiscussionsFromDiff', discussion);
+ }
+};
+
+export const deleteNote = ({ dispatch }, note) =>
+ axios.delete(note.path).then(() => {
+ dispatch('removeNote', note);
});
export const updateNote = ({ commit, dispatch }, { endpoint, note }) =>
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index 03281aa1317..12ee1ce2f0c 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -38,7 +38,9 @@ export default {
},
computed: {
statusTitle() {
- return sprintf(s__('Commits|Commit: %{commitText}'), { commitText: this.ciStatus.text });
+ return sprintf(s__('PipelineStatusTooltip|Pipeline: %{ciStatus}'), {
+ ciStatus: this.ciStatus.text,
+ });
},
},
mounted() {
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment.js b/app/assets/javascripts/visual_review_toolbar/components/comment.js
deleted file mode 100644
index a03dc14b319..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/comment.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { nextView } from '../store';
-import { localStorage, COMMENT_BOX, LOGOUT, STORAGE_MR_ID, STORAGE_TOKEN } from '../shared';
-import { clearNote } from './note';
-import { buttonClearStyles } from './utils';
-import { addForm } from './wrapper';
-import { changeSelectedMr, selectedMrNote } from './comment_mr_note';
-import postComment from './comment_post';
-import { saveComment, getSavedComment } from './comment_storage';
-
-const comment = state => {
- const savedComment = getSavedComment();
-
- return `
- <div>
- <textarea id="${COMMENT_BOX}" name="${COMMENT_BOX}" rows="3" placeholder="Enter your feedback or idea" class="gitlab-input" aria-required="true">${savedComment}</textarea>
- ${selectedMrNote(state)}
- <p class="gitlab-metadata-note">Additional metadata will be included: browser, OS, current page, user agent, and viewport dimensions.</p>
- </div>
- <div class="gitlab-button-wrapper">
- <button class="gitlab-button gitlab-button-success" style="${buttonClearStyles}" type="button" id="gitlab-comment-button"> Send feedback </button>
- <button class="gitlab-button gitlab-button-secondary" style="${buttonClearStyles}" type="button" id="${LOGOUT}"> Log out </button>
- </div>
- `;
-};
-
-// This function is here becaause it is called only from the comment view
-// If we reach a design where we can logout from multiple views, promote this
-// to it's own package
-const logoutUser = state => {
- localStorage.removeItem(STORAGE_TOKEN);
- localStorage.removeItem(STORAGE_MR_ID);
- state.token = '';
- state.mergeRequestId = '';
-
- clearNote();
- addForm(nextView(state, COMMENT_BOX));
-};
-
-export { changeSelectedMr, comment, logoutUser, postComment, saveComment };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js b/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js
deleted file mode 100644
index da67763261c..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { nextView } from '../store';
-import { localStorage, CHANGE_MR_ID_BUTTON, COMMENT_BOX, STORAGE_MR_ID } from '../shared';
-import { clearNote } from './note';
-import { buttonClearStyles } from './utils';
-import { addForm } from './wrapper';
-
-const selectedMrNote = state => {
- const { mrUrl, projectPath, mergeRequestId } = state;
-
- const mrLink = `${mrUrl}/${projectPath}/merge_requests/${mergeRequestId}`;
-
- return `
- <p class="gitlab-metadata-note">
- This posts to merge request <a class="gitlab-link" href="${mrLink}">!${mergeRequestId}</a>.
- <button style="${buttonClearStyles}" type="button" id="${CHANGE_MR_ID_BUTTON}" class="gitlab-link gitlab-link-button">Change</button>
- </p>
- `;
-};
-
-const clearMrId = state => {
- localStorage.removeItem(STORAGE_MR_ID);
- state.mergeRequestId = '';
-};
-
-const changeSelectedMr = state => {
- clearMrId(state);
- clearNote();
- addForm(nextView(state, COMMENT_BOX));
-};
-
-export { changeSelectedMr, selectedMrNote };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_post.js b/app/assets/javascripts/visual_review_toolbar/components/comment_post.js
deleted file mode 100644
index ee5f2b62425..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/comment_post.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import { BLACK, COMMENT_BOX, MUTED } from '../shared';
-import { clearSavedComment } from './comment_storage';
-import { clearNote, postError } from './note';
-import { selectCommentBox, selectCommentButton, selectNote, selectNoteContainer } from './utils';
-
-const resetCommentButton = () => {
- const commentButton = selectCommentButton();
-
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- commentButton.innerText = 'Send feedback';
- commentButton.classList.replace('gitlab-button-secondary', 'gitlab-button-success');
- commentButton.style.opacity = 1;
-};
-
-const resetCommentBox = () => {
- const commentBox = selectCommentBox();
- commentBox.style.pointerEvents = 'auto';
- commentBox.style.color = BLACK;
-};
-
-const resetCommentText = () => {
- const commentBox = selectCommentBox();
- commentBox.value = '';
- clearSavedComment();
-};
-
-const resetComment = () => {
- resetCommentButton();
- resetCommentBox();
- resetCommentText();
-};
-
-const confirmAndClear = feedbackInfo => {
- const commentButton = selectCommentButton();
- const currentNote = selectNote();
- const noteContainer = selectNoteContainer();
-
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- commentButton.innerText = 'Feedback sent';
- noteContainer.style.visibility = 'visible';
- currentNote.insertAdjacentHTML('beforeend', feedbackInfo);
-
- setTimeout(resetComment, 1000);
- setTimeout(clearNote, 6000);
-};
-
-const setInProgressState = () => {
- const commentButton = selectCommentButton();
- const commentBox = selectCommentBox();
-
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- commentButton.innerText = 'Sending feedback';
- commentButton.classList.replace('gitlab-button-success', 'gitlab-button-secondary');
- commentButton.style.opacity = 0.5;
- commentBox.style.color = MUTED;
- commentBox.style.pointerEvents = 'none';
-};
-
-const commentErrors = error => {
- switch (error.status) {
- case 401:
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- return 'Unauthorized. You may have entered an incorrect authentication token.';
- case 404:
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- return 'Not found. You may have entered an incorrect merge request ID.';
- default:
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- return `Your comment could not be sent. Please try again. Error: ${error.message}`;
- }
-};
-
-const postComment = ({
- platform,
- browser,
- userAgent,
- innerWidth,
- innerHeight,
- projectId,
- projectPath,
- mergeRequestId,
- mrUrl,
- token,
-}) => {
- // Clear any old errors
- clearNote(COMMENT_BOX);
-
- setInProgressState();
-
- const commentText = selectCommentBox().value.trim();
- // Get the href at the last moment to support SPAs
- const { href } = window.location;
-
- if (!commentText) {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- postError('Your comment appears to be empty.', COMMENT_BOX);
- resetCommentBox();
- resetCommentButton();
- return;
- }
-
- const detailText = `
- \n
-<details>
- <summary>Metadata</summary>
- Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}.
- <br /><br />
- <em>User agent: ${userAgent}</em>
-</details>
- `;
-
- const url = `
- ${mrUrl}/api/v4/projects/${projectId}/merge_requests/${mergeRequestId}/discussions`;
-
- const body = `${commentText} ${detailText}`;
-
- fetch(url, {
- method: 'POST',
- headers: {
- 'PRIVATE-TOKEN': token,
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ body }),
- })
- .then(response => {
- if (response.ok) {
- return response.json();
- }
-
- throw response;
- })
- .then(data => {
- const commentId = data.notes[0].id;
- const feedbackLink = `${mrUrl}/${projectPath}/merge_requests/${mergeRequestId}#note_${commentId}`;
- const feedbackInfo = `Feedback sent. View at <a class="gitlab-link" href="${feedbackLink}">${projectPath} !${mergeRequestId} (comment ${commentId})</a>`;
- confirmAndClear(feedbackInfo);
- })
- .catch(err => {
- postError(commentErrors(err), COMMENT_BOX);
- resetCommentBox();
- resetCommentButton();
- });
-};
-
-export default postComment;
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js b/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js
deleted file mode 100644
index 49c9400437e..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { selectCommentBox } from './utils';
-import { sessionStorage, STORAGE_COMMENT } from '../shared';
-
-const getSavedComment = () => sessionStorage.getItem(STORAGE_COMMENT) || '';
-
-const saveComment = () => {
- const currentComment = selectCommentBox();
-
- // This may be added to any view via top-level beforeunload listener
- // so let's skip if it does not apply
- if (currentComment && currentComment.value) {
- sessionStorage.setItem(STORAGE_COMMENT, currentComment.value);
- }
-};
-
-const clearSavedComment = () => {
- sessionStorage.removeItem(STORAGE_COMMENT);
-};
-
-export { getSavedComment, saveComment, clearSavedComment };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/form_elements.js b/app/assets/javascripts/visual_review_toolbar/components/form_elements.js
deleted file mode 100644
index 608488a6fea..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/form_elements.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { REMEMBER_ITEM } from '../shared';
-import { buttonClearStyles } from './utils';
-
-/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
-const rememberBox = (rememberText = 'Remember me') => `
- <div class="gitlab-checkbox-wrapper">
- <input type="checkbox" id="${REMEMBER_ITEM}" name="${REMEMBER_ITEM}" value="remember">
- <label for="${REMEMBER_ITEM}" class="gitlab-checkbox-label">${rememberText}</label>
- </div>
-`;
-
-const submitButton = buttonId => `
- <div class="gitlab-button-wrapper">
- <button class="gitlab-button-wide gitlab-button gitlab-button-success" style="${buttonClearStyles}" type="button" id="${buttonId}"> Submit </button>
- </div>
-`;
-export { rememberBox, submitButton };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/index.js b/app/assets/javascripts/visual_review_toolbar/components/index.js
deleted file mode 100644
index e88b3637ad8..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { changeSelectedMr, comment, logoutUser, postComment, saveComment } from './comment';
-import { authorizeUser, login } from './login';
-import { addMr, mrForm } from './mr_id';
-import { note } from './note';
-import { selectContainer, selectForm } from './utils';
-import { buttonAndForm, toggleForm } from './wrapper';
-
-export {
- addMr,
- authorizeUser,
- buttonAndForm,
- changeSelectedMr,
- comment,
- login,
- logoutUser,
- mrForm,
- note,
- postComment,
- saveComment,
- selectContainer,
- selectForm,
- toggleForm,
-};
diff --git a/app/assets/javascripts/visual_review_toolbar/components/login.js b/app/assets/javascripts/visual_review_toolbar/components/login.js
deleted file mode 100644
index 20ab01bc690..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/login.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { nextView } from '../store';
-import { localStorage, LOGIN, TOKEN_BOX, STORAGE_TOKEN } from '../shared';
-import { clearNote, postError } from './note';
-import { rememberBox, submitButton } from './form_elements';
-import { selectRemember, selectToken } from './utils';
-import { addForm } from './wrapper';
-
-const labelText = `
- Enter your <a class="gitlab-link" href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html">personal access token</a>
-`;
-
-const login = `
- <div>
- <label for="${TOKEN_BOX}" class="gitlab-label">${labelText}</label>
- <input class="gitlab-input" type="password" id="${TOKEN_BOX}" name="${TOKEN_BOX}" autocomplete="current-password" aria-required="true">
- </div>
- ${rememberBox()}
- ${submitButton(LOGIN)}
-`;
-
-const storeToken = (token, state) => {
- const rememberMe = selectRemember().checked;
-
- if (rememberMe) {
- localStorage.setItem(STORAGE_TOKEN, token);
- }
-
- state.token = token;
-};
-
-const authorizeUser = state => {
- // Clear any old errors
- clearNote(TOKEN_BOX);
-
- const token = selectToken().value;
-
- if (!token) {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- postError('Please enter your token.', TOKEN_BOX);
- return;
- }
-
- storeToken(token, state);
- addForm(nextView(state, LOGIN));
-};
-
-export { authorizeUser, login, storeToken };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/mr_id.js b/app/assets/javascripts/visual_review_toolbar/components/mr_id.js
deleted file mode 100644
index 695b3af8aa0..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/mr_id.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import { nextView } from '../store';
-import { MR_ID, MR_ID_BUTTON, STORAGE_MR_ID, localStorage } from '../shared';
-import { clearNote, postError } from './note';
-import { rememberBox, submitButton } from './form_elements';
-import { selectForm, selectMrBox, selectRemember } from './utils';
-import { addForm } from './wrapper';
-
-/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
-const mrLabel = `Enter your merge request ID`;
-/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
-const mrRememberText = `Remember this number`;
-
-const mrForm = `
- <div>
- <label for="${MR_ID}" class="gitlab-label">${mrLabel}</label>
- <input class="gitlab-input" type="text" pattern="[1-9][0-9]*" id="${MR_ID}" name="${MR_ID}" placeholder="e.g., 321" aria-required="true">
- </div>
- ${rememberBox(mrRememberText)}
- ${submitButton(MR_ID_BUTTON)}
-`;
-
-const storeMR = (id, state) => {
- const rememberMe = selectRemember().checked;
-
- if (rememberMe) {
- localStorage.setItem(STORAGE_MR_ID, id);
- }
-
- state.mergeRequestId = id;
-};
-
-const getFormError = (mrNumber, form) => {
- if (!mrNumber) {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- return 'Please enter your merge request ID number.';
- }
-
- if (!form.checkValidity()) {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- return 'Please remove any non-number values from the field.';
- }
-
- return null;
-};
-
-const addMr = state => {
- // Clear any old errors
- clearNote(MR_ID);
-
- const mrNumber = selectMrBox().value;
- const form = selectForm();
- const formError = getFormError(mrNumber, form);
-
- if (formError) {
- postError(formError, MR_ID);
- return;
- }
-
- storeMR(mrNumber, state);
- addForm(nextView(state, MR_ID));
-};
-
-export { addMr, mrForm, storeMR };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/note.js b/app/assets/javascripts/visual_review_toolbar/components/note.js
deleted file mode 100644
index 9cddcb710f2..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/note.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { NOTE, NOTE_CONTAINER, RED } from '../shared';
-import { selectById, selectNote, selectNoteContainer } from './utils';
-
-const note = `
- <div id="${NOTE_CONTAINER}" style="visibility: hidden;">
- <p id="${NOTE}" class="gitlab-message"></p>
- </div>
-`;
-
-const clearNote = inputId => {
- const currentNote = selectNote();
- const noteContainer = selectNoteContainer();
-
- currentNote.innerText = '';
- currentNote.style.color = '';
- noteContainer.style.visibility = 'hidden';
-
- if (inputId) {
- const field = document.getElementById(inputId);
- field.style.borderColor = '';
- }
-};
-
-const postError = (message, inputId) => {
- const currentNote = selectNote();
- const noteContainer = selectNoteContainer();
- const field = selectById(inputId);
- field.style.borderColor = RED;
- currentNote.style.color = RED;
- currentNote.innerText = message;
- noteContainer.style.visibility = 'visible';
- setTimeout(clearNote.bind(null, inputId), 5000);
-};
-
-export { clearNote, note, postError };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/utils.js b/app/assets/javascripts/visual_review_toolbar/components/utils.js
deleted file mode 100644
index 4ec9bd4a32a..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/utils.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* global document */
-
-import {
- COLLAPSE_BUTTON,
- COMMENT_BOX,
- COMMENT_BUTTON,
- FORM,
- FORM_CONTAINER,
- MR_ID,
- NOTE,
- NOTE_CONTAINER,
- REMEMBER_ITEM,
- REVIEW_CONTAINER,
- TOKEN_BOX,
-} from '../shared';
-
-// this style must be applied inline in a handful of components
-/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
-const buttonClearStyles = `
- -webkit-appearance: none;
-`;
-
-// selector functions to abstract out a little
-const selectById = id => document.getElementById(id);
-const selectCollapseButton = () => document.getElementById(COLLAPSE_BUTTON);
-const selectCommentBox = () => document.getElementById(COMMENT_BOX);
-const selectCommentButton = () => document.getElementById(COMMENT_BUTTON);
-const selectContainer = () => document.getElementById(REVIEW_CONTAINER);
-const selectForm = () => document.getElementById(FORM);
-const selectFormContainer = () => document.getElementById(FORM_CONTAINER);
-const selectMrBox = () => document.getElementById(MR_ID);
-const selectNote = () => document.getElementById(NOTE);
-const selectNoteContainer = () => document.getElementById(NOTE_CONTAINER);
-const selectRemember = () => document.getElementById(REMEMBER_ITEM);
-const selectToken = () => document.getElementById(TOKEN_BOX);
-
-export {
- buttonClearStyles,
- selectById,
- selectCollapseButton,
- selectContainer,
- selectCommentBox,
- selectCommentButton,
- selectForm,
- selectFormContainer,
- selectMrBox,
- selectNote,
- selectNoteContainer,
- selectRemember,
- selectToken,
-};
diff --git a/app/assets/javascripts/visual_review_toolbar/components/wrapper.js b/app/assets/javascripts/visual_review_toolbar/components/wrapper.js
deleted file mode 100644
index fdf8ad7c41f..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/wrapper.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import { CLEAR, FORM, FORM_CONTAINER, WHITE } from '../shared';
-import {
- selectCollapseButton,
- selectForm,
- selectFormContainer,
- selectNoteContainer,
-} from './utils';
-import { collapseButton, commentIcon, compressIcon } from './wrapper_icons';
-
-const form = content => `
- <form id="${FORM}" novalidate>
- ${content}
- </form>
-`;
-
-const buttonAndForm = content => `
- <div id="${FORM_CONTAINER}" class="gitlab-form-open">
- ${collapseButton}
- ${form(content)}
- </div>
-`;
-
-const addForm = nextForm => {
- const formWrapper = selectForm();
- formWrapper.innerHTML = nextForm;
-};
-
-function toggleForm() {
- const toggleButton = selectCollapseButton();
- const currentForm = selectForm();
- const formContainer = selectFormContainer();
- const noteContainer = selectNoteContainer();
- const OPEN = 'open';
- const CLOSED = 'closed';
-
- /*
- You may wonder why we spread the arrays before we reverse them.
- In the immortal words of MDN,
- Careful: reverse is destructive. It also changes the original array
- */
-
- const openButtonClasses = ['gitlab-collapse-closed', 'gitlab-collapse-open'];
- const closedButtonClasses = [...openButtonClasses].reverse();
- const openContainerClasses = ['gitlab-wrapper-closed', 'gitlab-wrapper-open'];
- const closedContainerClasses = [...openContainerClasses].reverse();
-
- const stateVals = {
- [OPEN]: {
- buttonClasses: openButtonClasses,
- containerClasses: openContainerClasses,
- icon: compressIcon,
- display: 'flex',
- backgroundColor: WHITE,
- },
- [CLOSED]: {
- buttonClasses: closedButtonClasses,
- containerClasses: closedContainerClasses,
- icon: commentIcon,
- display: 'none',
- backgroundColor: CLEAR,
- },
- };
-
- const nextState = toggleButton.classList.contains('gitlab-collapse-open') ? CLOSED : OPEN;
- const currentVals = stateVals[nextState];
-
- formContainer.classList.replace(...currentVals.containerClasses);
- formContainer.style.backgroundColor = currentVals.backgroundColor;
- formContainer.classList.toggle('gitlab-form-open');
- currentForm.style.display = currentVals.display;
- toggleButton.classList.replace(...currentVals.buttonClasses);
- toggleButton.innerHTML = currentVals.icon;
-
- if (noteContainer && noteContainer.innerText.length > 0) {
- noteContainer.style.display = currentVals.display;
- }
-}
-
-export { addForm, buttonAndForm, toggleForm };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/wrapper_icons.js b/app/assets/javascripts/visual_review_toolbar/components/wrapper_icons.js
deleted file mode 100644
index b686fd4f5c2..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/components/wrapper_icons.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { buttonClearStyles } from './utils';
-
-const commentIcon = `
- <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/comment</title><path d="M4 11.132l1.446-.964A1 1 0 0 1 6 10h5a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v6.132zM6.303 12l-2.748 1.832A1 1 0 0 1 2 13V5a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v4a3 3 0 0 1-3 3H6.303z" id="gitlab-comment-icon"/></svg>
-`;
-
-const compressIcon = `
- <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/compress</title><path d="M5.27 12.182l-1.562 1.561a1 1 0 0 1-1.414 0h-.001a1 1 0 0 1 0-1.415l1.56-1.56L2.44 9.353a.5.5 0 0 1 .353-.854H7.09a.5.5 0 0 1 .5.5v4.294a.5.5 0 0 1-.853.353l-1.467-1.465zm6.911-6.914l1.464 1.464a.5.5 0 0 1-.353.854H8.999a.5.5 0 0 1-.5-.5V2.793a.5.5 0 0 1 .854-.354l1.414 1.415 1.56-1.561a1 1 0 1 1 1.415 1.414l-1.561 1.56z" id="gitlab-compress-icon"/></svg>
-`;
-
-const collapseButton = `
- <button id='gitlab-collapse' style='${buttonClearStyles}' class='gitlab-button gitlab-button-secondary gitlab-collapse gitlab-collapse-open'>${compressIcon}</button>
-`;
-
-export { commentIcon, compressIcon, collapseButton };
diff --git a/app/assets/javascripts/visual_review_toolbar/index.js b/app/assets/javascripts/visual_review_toolbar/index.js
deleted file mode 100644
index 67b3fadd772..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/index.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import './styles/toolbar.css';
-
-import { buttonAndForm, note, selectForm, selectContainer } from './components';
-import { REVIEW_CONTAINER } from './shared';
-import { eventLookup, getInitialView, initializeGlobalListeners, initializeState } from './store';
-
-/*
-
- Welcome to the visual review toolbar files. A few useful notes:
-
- - These files build a static script that is served from our webpack
- assets folder. (https://gitlab.com/assets/webpack/visual_review_toolbar.js)
-
- - To compile this file, run `yarn webpack-vrt`.
-
- - Vue is not used in these files because we do not want to ask users to
- install another library at this time. It's all pure vanilla javascript.
-
-*/
-
-window.addEventListener('load', () => {
- initializeState(window, document);
-
- const mainContent = buttonAndForm(getInitialView());
- const container = document.createElement('div');
- container.setAttribute('id', REVIEW_CONTAINER);
- container.insertAdjacentHTML('beforeend', note);
- container.insertAdjacentHTML('beforeend', mainContent);
-
- document.body.insertBefore(container, document.body.firstChild);
-
- selectContainer().addEventListener('click', event => {
- eventLookup(event.target.id)();
- });
-
- selectForm().addEventListener('submit', event => {
- // this is important to prevent the form from adding data
- // as URL params and inadvertently revealing secrets
- event.preventDefault();
-
- const id =
- event.target.querySelector('.gitlab-button-wrapper') &&
- event.target.querySelector('.gitlab-button-wrapper').getElementsByTagName('button')[0] &&
- event.target.querySelector('.gitlab-button-wrapper').getElementsByTagName('button')[0].id;
-
- // even if this is called with false, it's ok; it will get the default no-op
- eventLookup(id)();
- });
-
- initializeGlobalListeners();
-});
diff --git a/app/assets/javascripts/visual_review_toolbar/shared/constants.js b/app/assets/javascripts/visual_review_toolbar/shared/constants.js
deleted file mode 100644
index 0d5b666ab0a..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/shared/constants.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// component selectors
-const CHANGE_MR_ID_BUTTON = 'gitlab-change-mr';
-const COLLAPSE_BUTTON = 'gitlab-collapse';
-const COMMENT_BOX = 'gitlab-comment';
-const COMMENT_BUTTON = 'gitlab-comment-button';
-const FORM = 'gitlab-form';
-const FORM_CONTAINER = 'gitlab-form-wrapper';
-const LOGIN = 'gitlab-login-button';
-const LOGOUT = 'gitlab-logout-button';
-const MR_ID = 'gitlab-submit-mr';
-const MR_ID_BUTTON = 'gitlab-submit-mr-button';
-const NOTE = 'gitlab-validation-note';
-const NOTE_CONTAINER = 'gitlab-note-wrapper';
-const REMEMBER_ITEM = 'gitlab-remember-item';
-const REVIEW_CONTAINER = 'gitlab-review-container';
-const TOKEN_BOX = 'gitlab-token';
-
-// Storage keys
-const STORAGE_PREFIX = '--gitlab'; // Using `--` to make the prefix more unique
-const STORAGE_MR_ID = `${STORAGE_PREFIX}-merge-request-id`;
-const STORAGE_TOKEN = `${STORAGE_PREFIX}-token`;
-const STORAGE_COMMENT = `${STORAGE_PREFIX}-comment`;
-
-// colors — these are applied programmatically
-// rest of styles belong in ./styles
-const BLACK = 'rgba(46, 46, 46, 1)';
-const CLEAR = 'rgba(255, 255, 255, 0)';
-const MUTED = 'rgba(223, 223, 223, 0.5)';
-const RED = 'rgba(219, 59, 33, 1)';
-const WHITE = 'rgba(250, 250, 250, 1)';
-
-export {
- CHANGE_MR_ID_BUTTON,
- COLLAPSE_BUTTON,
- COMMENT_BOX,
- COMMENT_BUTTON,
- FORM,
- FORM_CONTAINER,
- LOGIN,
- LOGOUT,
- MR_ID,
- MR_ID_BUTTON,
- NOTE,
- NOTE_CONTAINER,
- REMEMBER_ITEM,
- REVIEW_CONTAINER,
- TOKEN_BOX,
- STORAGE_MR_ID,
- STORAGE_TOKEN,
- STORAGE_COMMENT,
- BLACK,
- CLEAR,
- MUTED,
- RED,
- WHITE,
-};
diff --git a/app/assets/javascripts/visual_review_toolbar/shared/index.js b/app/assets/javascripts/visual_review_toolbar/shared/index.js
deleted file mode 100644
index d8ccb170592..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/shared/index.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import {
- CHANGE_MR_ID_BUTTON,
- COLLAPSE_BUTTON,
- COMMENT_BOX,
- COMMENT_BUTTON,
- FORM,
- FORM_CONTAINER,
- LOGIN,
- LOGOUT,
- MR_ID,
- MR_ID_BUTTON,
- NOTE,
- NOTE_CONTAINER,
- REMEMBER_ITEM,
- REVIEW_CONTAINER,
- TOKEN_BOX,
- STORAGE_MR_ID,
- STORAGE_TOKEN,
- STORAGE_COMMENT,
- BLACK,
- CLEAR,
- MUTED,
- RED,
- WHITE,
-} from './constants';
-
-import { localStorage, sessionStorage } from './storage_utils';
-
-export {
- localStorage,
- sessionStorage,
- CHANGE_MR_ID_BUTTON,
- COLLAPSE_BUTTON,
- COMMENT_BOX,
- COMMENT_BUTTON,
- FORM,
- FORM_CONTAINER,
- LOGIN,
- LOGOUT,
- MR_ID,
- MR_ID_BUTTON,
- NOTE,
- NOTE_CONTAINER,
- REMEMBER_ITEM,
- REVIEW_CONTAINER,
- TOKEN_BOX,
- STORAGE_MR_ID,
- STORAGE_TOKEN,
- STORAGE_COMMENT,
- BLACK,
- CLEAR,
- MUTED,
- RED,
- WHITE,
-};
diff --git a/app/assets/javascripts/visual_review_toolbar/shared/storage_utils.js b/app/assets/javascripts/visual_review_toolbar/shared/storage_utils.js
deleted file mode 100644
index 00456d3536e..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/shared/storage_utils.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { setUsingGracefulStorageFlag } from '../store/state';
-
-const TEST_KEY = 'gitlab-storage-test';
-
-const createStorageStub = () => {
- const items = {};
-
- return {
- getItem(key) {
- return items[key];
- },
- setItem(key, value) {
- items[key] = value;
- },
- removeItem(key) {
- delete items[key];
- },
- };
-};
-
-const hasStorageSupport = storage => {
- // Support test taken from https://stackoverflow.com/a/11214467/1708147
- try {
- storage.setItem(TEST_KEY, TEST_KEY);
- storage.removeItem(TEST_KEY);
- setUsingGracefulStorageFlag(true);
-
- return true;
- } catch (err) {
- setUsingGracefulStorageFlag(false);
- return false;
- }
-};
-
-const useGracefulStorage = storage =>
- // If a browser does not support local storage, let's return a graceful implementation.
- hasStorageSupport(storage) ? storage : createStorageStub();
-
-const localStorage = useGracefulStorage(window.localStorage);
-const sessionStorage = useGracefulStorage(window.sessionStorage);
-
-export { localStorage, sessionStorage };
diff --git a/app/assets/javascripts/visual_review_toolbar/store/events.js b/app/assets/javascripts/visual_review_toolbar/store/events.js
deleted file mode 100644
index c9095c77ef1..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/store/events.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import {
- addMr,
- authorizeUser,
- changeSelectedMr,
- logoutUser,
- postComment,
- saveComment,
- toggleForm,
-} from '../components';
-
-import {
- CHANGE_MR_ID_BUTTON,
- COLLAPSE_BUTTON,
- COMMENT_BUTTON,
- LOGIN,
- LOGOUT,
- MR_ID_BUTTON,
-} from '../shared';
-
-import { state } from './state';
-import debounce from './utils';
-
-const noop = () => {};
-
-// State needs to be bound here to be acted on
-// because these are called by click events and
-// as such are called with only the `event` object
-const eventLookup = id => {
- switch (id) {
- case CHANGE_MR_ID_BUTTON:
- return () => {
- saveComment();
- changeSelectedMr(state);
- };
- case COLLAPSE_BUTTON:
- return toggleForm;
- case COMMENT_BUTTON:
- return postComment.bind(null, state);
- case LOGIN:
- return authorizeUser.bind(null, state);
- case LOGOUT:
- return () => {
- saveComment();
- logoutUser(state);
- };
- case MR_ID_BUTTON:
- return addMr.bind(null, state);
- default:
- return noop;
- }
-};
-
-const updateWindowSize = wind => {
- state.innerWidth = wind.innerWidth;
- state.innerHeight = wind.innerHeight;
-};
-
-const initializeGlobalListeners = () => {
- window.addEventListener('resize', debounce(updateWindowSize.bind(null, window), 200));
- window.addEventListener('beforeunload', event => {
- if (state.usingGracefulStorage) {
- // if there is no browser storage support, reloading will lose the comment; this way, the user will be warned
- // we assign the return value because it is required by Chrome see: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#Example,
- event.preventDefault();
- /* eslint-disable-next-line no-param-reassign */
- event.returnValue = '';
- }
-
- saveComment();
- });
-};
-
-export { eventLookup, initializeGlobalListeners };
diff --git a/app/assets/javascripts/visual_review_toolbar/store/index.js b/app/assets/javascripts/visual_review_toolbar/store/index.js
deleted file mode 100644
index 07c8dd6f1d2..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/store/index.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { eventLookup, initializeGlobalListeners } from './events';
-import { nextView, getInitialView, initializeState, setUsingGracefulStorageFlag } from './state';
-
-export {
- eventLookup,
- getInitialView,
- initializeGlobalListeners,
- initializeState,
- nextView,
- setUsingGracefulStorageFlag,
-};
diff --git a/app/assets/javascripts/visual_review_toolbar/store/state.js b/app/assets/javascripts/visual_review_toolbar/store/state.js
deleted file mode 100644
index b7853bb0723..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/store/state.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import { comment, login, mrForm } from '../components';
-import { localStorage, COMMENT_BOX, LOGIN, MR_ID, STORAGE_MR_ID, STORAGE_TOKEN } from '../shared';
-
-const state = {
- browser: '',
- usingGracefulStorage: '',
- innerWidth: '',
- innerHeight: '',
- mergeRequestId: '',
- mrUrl: '',
- platform: '',
- projectId: '',
- userAgent: '',
- token: '',
-};
-
-// adapted from https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator#Example_2_Browser_detect_and_return_an_index
-const getBrowserId = sUsrAg => {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- const aKeys = ['MSIE', 'Edge', 'Firefox', 'Safari', 'Chrome', 'Opera'];
- let nIdx = aKeys.length - 1;
-
- for (nIdx; nIdx > -1 && sUsrAg.indexOf(aKeys[nIdx]) === -1; nIdx -= 1);
- return aKeys[nIdx];
-};
-
-const nextView = (appState, form = 'none') => {
- const formsList = {
- [COMMENT_BOX]: currentState => (currentState.token ? mrForm : login),
- [LOGIN]: currentState => (currentState.mergeRequestId ? comment(currentState) : mrForm),
- [MR_ID]: currentState => (currentState.token ? comment(currentState) : login),
- none: currentState => {
- if (!currentState.token) {
- return login;
- }
-
- if (currentState.token && !currentState.mergeRequestId) {
- return mrForm;
- }
-
- return comment(currentState);
- },
- };
-
- return formsList[form](appState);
-};
-
-const initializeState = (wind, doc) => {
- const {
- innerWidth,
- innerHeight,
- navigator: { platform, userAgent },
- } = wind;
-
- const browser = getBrowserId(userAgent);
-
- const scriptEl = doc.getElementById('review-app-toolbar-script');
- const { projectId, mergeRequestId, mrUrl, projectPath } = scriptEl.dataset;
-
- // This mutates our default state object above. It's weird but it makes the linter happy.
- Object.assign(state, {
- browser,
- innerWidth,
- innerHeight,
- mergeRequestId,
- mrUrl,
- platform,
- projectId,
- projectPath,
- userAgent,
- });
-
- return state;
-};
-
-const getInitialView = () => {
- const token = localStorage.getItem(STORAGE_TOKEN);
- const mrId = localStorage.getItem(STORAGE_MR_ID);
-
- if (token) {
- state.token = token;
- }
-
- if (mrId) {
- state.mergeRequestId = mrId;
- }
-
- return nextView(state);
-};
-
-const setUsingGracefulStorageFlag = flag => {
- state.usingGracefulStorage = !flag;
-};
-
-export { initializeState, getInitialView, nextView, setUsingGracefulStorageFlag, state };
diff --git a/app/assets/javascripts/visual_review_toolbar/store/utils.js b/app/assets/javascripts/visual_review_toolbar/store/utils.js
deleted file mode 100644
index 5cf145351b3..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/store/utils.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const debounce = (fn, time) => {
- let current;
-
- const debounced = () => {
- if (current) {
- clearTimeout(current);
- }
-
- current = setTimeout(fn, time);
- };
-
- return debounced;
-};
-
-export default debounce;
diff --git a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css b/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
deleted file mode 100644
index d1a8d66ef40..00000000000
--- a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- As a standalone script, the toolbar has its own css
- */
-
-#gitlab-collapse > * {
- pointer-events: none;
-}
-
-#gitlab-comment {
- background-color: #fafafa;
-}
-
-#gitlab-form {
- display: flex;
- flex-direction: column;
- width: 100%;
- margin-bottom: 0;
-}
-
-#gitlab-note-wrapper {
- display: flex;
- flex-direction: column;
- background-color: #fafafa;
- border-radius: 4px;
- margin-bottom: .5rem;
- padding: 1rem;
-}
-
-#gitlab-form-wrapper {
- overflow: auto;
- display: flex;
- flex-direction: row-reverse;
- border-radius: 4px;
-}
-
-#gitlab-review-container {
- max-width: 22rem;
- max-height: 22rem;
- overflow: auto;
- display: flex;
- flex-direction: column;
- position: fixed;
- bottom: 1rem;
- right: 1rem;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, Cantarell,
- 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
- 'Noto Color Emoji';
- font-size: .8rem;
- font-weight: 400;
- color: #2e2e2e;
- z-index: 9999; /* toolbar should always be on top */
-}
-
-.gitlab-wrapper-open {
- max-width: 22rem;
- max-height: 22rem;
-}
-
-.gitlab-wrapper-closed {
- max-width: 3.4rem;
- max-height: 3.4rem;
-}
-
-.gitlab-button {
- cursor: pointer;
- transition: background-color 100ms linear, border-color 100ms linear, color 100ms linear, box-shadow 100ms linear;
-}
-
-.gitlab-button-secondary {
- background: none #fafafa;
- margin: 0 .5rem;
- border: 1px solid #e3e3e3;
-}
-
-.gitlab-button-secondary:hover {
- background-color: #f0f0f0;
- border-color: #e3e3e3;
- color: #2e2e2e;
-}
-
-.gitlab-button-secondary:active {
- color: #2e2e2e;
- background-color: #e1e1e1;
- border-color: #dadada;
-}
-
-.gitlab-button-success:hover {
- color: #fff;
- background-color: #137e3f;
- border-color: #127339;
-}
-
-.gitlab-button-success:active {
- background-color: #168f48;
- border-color: #12753a;
- color: #fff;
-}
-
-.gitlab-button-success {
- background-color: #1aaa55;
- border: 1px solid #168f48;
- color: #fff;
-}
-
-.gitlab-button-wide {
- width: 100%;
-}
-
-.gitlab-button-wrapper {
- margin-top: 0.5rem;
- display: flex;
- align-items: baseline;
- /*
- this makes sure the hit enter to submit picks the correct button
- on the comment view
- */
- flex-direction: row-reverse;
-}
-
-.gitlab-collapse {
- width: 2.4rem;
- height: 2.2rem;
- margin-left: 1rem;
- padding: .5rem;
-}
-
-.gitlab-collapse-closed {
- align-self: center;
-}
-
-.gitlab-checkbox-label {
- padding: 0 .2rem;
-}
-
-.gitlab-checkbox-wrapper {
- display: flex;
- align-items: baseline;
-}
-
-.gitlab-form-open {
- padding: 1rem;
- background-color: #fafafa;
-}
-
-.gitlab-label {
- font-weight: 600;
- display: inline-block;
- width: 100%;
-}
-
-.gitlab-link {
- color: #1b69b6;
- text-decoration: none;
- background-color: transparent;
- background-image: none;
-}
-
-.gitlab-link:hover {
- text-decoration: underline;
-}
-
-.gitlab-link-button {
- border: none;
- cursor: pointer;
- padding: 0 .15rem;
-}
-
-.gitlab-message {
- padding: .25rem 0;
- margin: 0;
- line-height: 1.2rem;
-}
-
-.gitlab-metadata-note {
- font-size: .7rem;
- line-height: 1rem;
- color: #666;
- margin-bottom: .5rem;
-}
-
-.gitlab-input {
- width: 100%;
- border: 1px solid #dfdfdf;
- border-radius: 4px;
- padding: .1rem .2rem;
- min-height: 2rem;
- max-width: 17rem;
-}
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index d2a961efff7..4b7899d469b 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -73,6 +73,11 @@ module NotesActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def update
@note = Notes::UpdateService.new(project, current_user, update_note_params).execute(note)
+ unless @note
+ head :gone
+ return
+ end
+
prepare_notes_for_rendering([@note])
respond_to do |format|
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index 5ecf4f114cf..da39d64c93d 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class JwtController < ApplicationController
+ skip_around_action :set_session_storage
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
before_action :authenticate_project_or_user
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 65d9b074eee..13e8453ed00 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -6,7 +6,7 @@ class Projects::NotesController < Projects::ApplicationController
include NotesHelper
include ToggleAwardEmoji
- before_action :whitelist_query_limiting, only: [:create]
+ before_action :whitelist_query_limiting, only: [:create, :update]
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index e6e3a440925..499d4918899 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -180,7 +180,7 @@ class Projects::PipelinesController < Projects::ApplicationController
else
project
.all_pipelines
- .includes(user: :status)
+ .includes(builds: :tags, user: :status)
.find_by!(id: params[:id])
.present(current_user: current_user)
end
diff --git a/app/graphql/functions/base_function.rb b/app/graphql/functions/base_function.rb
deleted file mode 100644
index 2512ecbd255..00000000000
--- a/app/graphql/functions/base_function.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-
-module Functions
- class BaseFunction < GraphQL::Function
- end
-end
diff --git a/app/graphql/functions/echo.rb b/app/graphql/functions/echo.rb
deleted file mode 100644
index 3104486faac..00000000000
--- a/app/graphql/functions/echo.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-module Functions
- class Echo < BaseFunction
- argument :text, GraphQL::STRING_TYPE
-
- description "Testing endpoint to validate the API with"
-
- def call(obj, args, ctx)
- username = ctx[:current_user]&.username
-
- "#{username.inspect} says: #{args[:text]}"
- end
- end
-end
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb
index 7edd14e48f7..4c8612c8f2e 100644
--- a/app/graphql/gitlab_schema.rb
+++ b/app/graphql/gitlab_schema.rb
@@ -49,7 +49,7 @@ class GitlabSchema < GraphQL::Schema
def id_from_object(object)
unless object.respond_to?(:to_global_id)
# This is an error in our schema and needs to be solved. So raise a
- # more meaningfull error message
+ # more meaningful error message
raise "#{object} does not implement `to_global_id`. "\
"Include `GlobalID::Identification` into `#{object.class}"
end
diff --git a/app/graphql/resolvers/echo_resolver.rb b/app/graphql/resolvers/echo_resolver.rb
new file mode 100644
index 00000000000..8076e1784ce
--- /dev/null
+++ b/app/graphql/resolvers/echo_resolver.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class EchoResolver < BaseResolver
+ argument :text, GraphQL::STRING_TYPE, required: true
+ description 'Testing endpoint to validate the API with'
+
+ def resolve(**args)
+ username = context[:current_user]&.username
+
+ "#{username.inspect} says: #{args[:text]}"
+ end
+ end
+end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 53d36b43576..c686300b25d 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -24,6 +24,6 @@ module Types
resolver: Resolvers::MetadataResolver,
description: 'Metadata about GitLab'
- field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new
+ field :echo, GraphQL::STRING_TYPE, null: false, resolver: Resolvers::EchoResolver
end
end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index f2b5b82b013..144df676304 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -105,14 +105,13 @@ module CiStatusHelper
path = pipelines_project_commit_path(project, commit, ref: ref)
render_status_with_link(
- 'commit',
commit.status(ref),
path,
tooltip_placement: tooltip_placement,
icon_size: 24)
end
- def render_status_with_link(type, status, path = nil, tooltip_placement: 'left', cssclass: '', container: 'body', icon_size: 16)
+ def render_status_with_link(status, path = nil, type: _('pipeline'), tooltip_placement: 'left', cssclass: '', container: 'body', icon_size: 16)
klass = "ci-status-link ci-status-icon-#{status.dasherize} d-inline-flex #{cssclass}"
title = "#{type.titleize}: #{ci_label_for_status(status)}"
data = { toggle: 'tooltip', placement: tooltip_placement, container: container }
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index 5678304ffcf..8855e0cdd70 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -106,9 +106,9 @@ module NotificationsHelper
end
end
- def notification_setting_icon(notification_setting)
+ def notification_setting_icon(notification_setting = nil)
sprite_icon(
- notification_setting.disabled? ? "notifications-off" : "notifications",
+ !notification_setting.present? || notification_setting.disabled? ? "notifications-off" : "notifications",
css_class: "icon notifications-icon js-notifications-icon"
)
end
diff --git a/app/models/analytics/cycle_analytics/project_stage.rb b/app/models/analytics/cycle_analytics/project_stage.rb
index 88c8cb40ccb..a312bd24e78 100644
--- a/app/models/analytics/cycle_analytics/project_stage.rb
+++ b/app/models/analytics/cycle_analytics/project_stage.rb
@@ -3,7 +3,12 @@
module Analytics
module CycleAnalytics
class ProjectStage < ApplicationRecord
+ include Analytics::CycleAnalytics::Stage
+
+ validates :project, presence: true
belongs_to :project
+
+ alias_attribute :parent, :project
end
end
end
diff --git a/app/models/concerns/analytics/cycle_analytics/stage.rb b/app/models/concerns/analytics/cycle_analytics/stage.rb
new file mode 100644
index 00000000000..0c603c2d5e6
--- /dev/null
+++ b/app/models/concerns/analytics/cycle_analytics/stage.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module Analytics
+ module CycleAnalytics
+ module Stage
+ extend ActiveSupport::Concern
+
+ included do
+ validates :name, presence: true
+ validates :start_event_identifier, presence: true
+ validates :end_event_identifier, presence: true
+ validate :validate_stage_event_pairs
+
+ enum start_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents.to_enum, _prefix: :start_event_identifier
+ enum end_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents.to_enum, _prefix: :end_event_identifier
+
+ alias_attribute :custom_stage?, :custom
+ end
+
+ def parent=(_)
+ raise NotImplementedError
+ end
+
+ def parent
+ raise NotImplementedError
+ end
+
+ def start_event
+ Gitlab::Analytics::CycleAnalytics::StageEvents[start_event_identifier].new(params_for_start_event)
+ end
+
+ def end_event
+ Gitlab::Analytics::CycleAnalytics::StageEvents[end_event_identifier].new(params_for_end_event)
+ end
+
+ def params_for_start_event
+ {}
+ end
+
+ def params_for_end_event
+ {}
+ end
+
+ def default_stage?
+ !custom
+ end
+
+ # The model that is going to be queried, Issue or MergeRequest
+ def subject_model
+ start_event.object_type
+ end
+
+ private
+
+ def validate_stage_event_pairs
+ return if start_event_identifier.nil? || end_event_identifier.nil?
+
+ unless pairing_rules.fetch(start_event.class, []).include?(end_event.class)
+ errors.add(:end_event, :not_allowed_for_the_given_start_event)
+ end
+ end
+
+ def pairing_rules
+ Gitlab::Analytics::CycleAnalytics::StageEvents.pairing_rules
+ end
+ end
+ end
+end
diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb
index 33f0be91632..85f5a2040c0 100644
--- a/app/models/deploy_token.rb
+++ b/app/models/deploy_token.rb
@@ -5,7 +5,7 @@ class DeployToken < ApplicationRecord
include TokenAuthenticatable
include PolicyActor
include Gitlab::Utils::StrongMemoize
- add_authentication_token_field :token
+ add_authentication_token_field :token, encrypted: :optional
AVAILABLE_SCOPES = %i(read_repository read_registry).freeze
GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token'.freeze
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 68586e7a1fd..bff5d348ca0 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -162,6 +162,14 @@ class Deployment < ApplicationRecord
deployed_at&.to_time&.in_time_zone&.to_s(:medium)
end
+ def deployed_by
+ # We use deployable's user if available because Ci::PlayBuildService
+ # does not update the deployment's user, just the one for the deployable.
+ # TODO: use deployment's user once https://gitlab.com/gitlab-org/gitlab-ce/issues/66442
+ # is completed.
+ deployable&.user || user
+ end
+
private
def ref_path
diff --git a/app/models/project.rb b/app/models/project.rb
index 10679fb1f85..66d5286196e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2175,8 +2175,7 @@ class Project < ApplicationRecord
hashed_storage?(:repository) &&
public? &&
repository_exists? &&
- Gitlab::CurrentSettings.hashed_storage_enabled &&
- Feature.enabled?(:object_pools, self, default_enabled: true)
+ Gitlab::CurrentSettings.hashed_storage_enabled
end
def leave_pool_repository
diff --git a/app/models/user.rb b/app/models/user.rb
index 6131a8dc710..6107aaa7fca 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -161,6 +161,8 @@ class User < ApplicationRecord
#
# Note: devise :validatable above adds validations for :email and :password
validates :name, presence: true, length: { maximum: 128 }
+ validates :first_name, length: { maximum: 255 }
+ validates :last_name, length: { maximum: 255 }
validates :email, confirmation: true
validates :notification_email, presence: true
validates :notification_email, devise_email: true, if: ->(user) { user.notification_email != user.email }
@@ -881,7 +883,15 @@ class User < ApplicationRecord
end
def first_name
- name.split.first unless name.blank?
+ read_attribute(:first_name) || begin
+ name.split(' ').first unless name.blank?
+ end
+ end
+
+ def last_name
+ read_attribute(:last_name) || begin
+ name.split(' ').drop(1).join(' ') unless name.blank?
+ end
end
def projects_limit_left
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index b8dee1b0789..e2634692dc7 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -502,6 +502,8 @@ class ProjectPolicy < BasePolicy
end
def feature_available?(feature)
+ return false unless project.project_feature
+
case project.project_feature.access_level(feature)
when ProjectFeature::DISABLED
false
diff --git a/app/serializers/deployment_entity.rb b/app/serializers/deployment_entity.rb
index d6466ad1cdd..8b967459173 100644
--- a/app/serializers/deployment_entity.rb
+++ b/app/serializers/deployment_entity.rb
@@ -21,7 +21,7 @@ class DeploymentEntity < Grape::Entity
expose :deployed_at
expose :tag
expose :last?
- expose :user, using: UserEntity
+ expose :deployed_by, as: :user, using: UserEntity
expose :deployable do |deployment, opts|
deployment.deployable.yield_self do |deployable|
diff --git a/app/services/application_settings/update_service.rb b/app/services/application_settings/update_service.rb
index 471df6e2d0c..8115585b7a8 100644
--- a/app/services/application_settings/update_service.rb
+++ b/app/services/application_settings/update_service.rb
@@ -7,7 +7,7 @@ module ApplicationSettings
attr_reader :params, :application_setting
def execute
- validate_classification_label(application_setting, :external_authorization_service_default_label)
+ validate_classification_label(application_setting, :external_authorization_service_default_label) unless bypass_external_auth?
if application_setting.errors.any?
return false
@@ -59,5 +59,9 @@ module ApplicationSettings
Group.find_by_full_path(group_full_path)&.id if group_full_path.present?
end
+
+ def bypass_external_auth?
+ params.key?(:external_authorization_service_enabled) && !Gitlab::Utils.to_boolean(params[:external_authorization_service_enabled])
+ end
end
end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 06e46595b95..a69678a4422 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -27,6 +27,7 @@ module MergeRequests
issuable.cache_merge_request_closes_issues!(current_user)
create_pipeline_for(issuable, current_user)
issuable.update_head_pipeline
+ Gitlab::UsageDataCounters::MergeRequestCounter.count(:create)
super
end
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index 384d1dd2e50..853faed9d85 100644
--- a/app/services/notes/update_service.rb
+++ b/app/services/notes/update_service.rb
@@ -8,24 +8,70 @@ module Notes
old_mentioned_users = note.mentioned_users.to_a
note.update(params.merge(updated_by: current_user))
- note.create_new_cross_references!(current_user)
- if note.previous_changes.include?('note')
- TodoService.new.update_note(note, current_user, old_mentioned_users)
+ only_commands = false
+
+ quick_actions_service = QuickActionsService.new(project, current_user)
+ if quick_actions_service.supported?(note)
+ content, update_params, message = quick_actions_service.execute(note, {})
+
+ only_commands = content.empty?
+
+ note.note = content
+ end
+
+ unless only_commands
+ note.create_new_cross_references!(current_user)
+
+ update_todos(note, old_mentioned_users)
+
+ update_suggestions(note)
end
- if note.supports_suggestion?
- Suggestion.transaction do
- note.suggestions.delete_all
- Suggestions::CreateService.new(note).execute
+ if quick_actions_service.commands_executed_count.to_i > 0
+ if update_params.present?
+ quick_actions_service.apply_updates(update_params, note)
+ note.commands_changes = update_params
end
- # We need to refresh the previous suggestions call cache
- # in order to get the new records.
- note.reset
+ if only_commands
+ delete_note(note, message)
+ note = nil
+ else
+ note.save
+ end
end
note
end
+
+ private
+
+ def delete_note(note, message)
+ # We must add the error after we call #save because errors are reset
+ # when #save is called
+ note.errors.add(:commands_only, message.presence || _('Commands did not apply'))
+
+ Notes::DestroyService.new(project, current_user).execute(note)
+ end
+
+ def update_suggestions(note)
+ return unless note.supports_suggestion?
+
+ Suggestion.transaction do
+ note.suggestions.delete_all
+ Suggestions::CreateService.new(note).execute
+ end
+
+ # We need to refresh the previous suggestions call cache
+ # in order to get the new records.
+ note.reset
+ end
+
+ def update_todos(note, old_mentioned_users)
+ return unless note.previous_changes.include?('note')
+
+ TodoService.new.update_note(note, current_user, old_mentioned_users)
+ end
end
end
diff --git a/app/services/self_monitoring/project/create_service.rb b/app/services/self_monitoring/project/create_service.rb
deleted file mode 100644
index c925c6a1610..00000000000
--- a/app/services/self_monitoring/project/create_service.rb
+++ /dev/null
@@ -1,219 +0,0 @@
-# frozen_string_literal: true
-
-module SelfMonitoring
- module Project
- class CreateService < ::BaseService
- include Stepable
- include Gitlab::Utils::StrongMemoize
-
- VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
- PROJECT_NAME = 'GitLab Instance Administration'
- PROJECT_DESCRIPTION = <<~HEREDOC
- This project is automatically generated and will be used to help monitor this GitLab instance.
- HEREDOC
-
- GROUP_NAME = 'GitLab Instance Administrators'
- GROUP_PATH = 'gitlab-instance-administrators'
-
- steps :validate_admins,
- :create_group,
- :create_project,
- :save_project_id,
- :add_group_members,
- :add_to_whitelist,
- :add_prometheus_manual_configuration
-
- def initialize
- super(nil)
- end
-
- def execute
- execute_steps
- end
-
- private
-
- def validate_admins
- unless instance_admins.any?
- log_error('No active admin user found')
- return error('No active admin user found')
- end
-
- success
- end
-
- def create_group
- if project_created?
- log_info(_('Instance administrators group already exists'))
- @group = application_settings.instance_administration_project.owner
- return success(group: @group)
- end
-
- admin_user = group_owner
- @group = ::Groups::CreateService.new(admin_user, create_group_params).execute
-
- if @group.persisted?
- success(group: @group)
- else
- error('Could not create group')
- end
- end
-
- def create_project
- if project_created?
- log_info(_('Instance administration project already exists'))
- @project = application_settings.instance_administration_project
- return success(project: project)
- end
-
- admin_user = group_owner
- @project = ::Projects::CreateService.new(admin_user, create_project_params).execute
-
- if project.persisted?
- success(project: project)
- else
- log_error(_("Could not create instance administration project. Errors: %{errors}") % { errors: project.errors.full_messages })
- error(_('Could not create project'))
- end
- end
-
- def save_project_id
- return success if project_created?
-
- result = ApplicationSettings::UpdateService.new(
- application_settings,
- group_owner,
- { instance_administration_project_id: @project.id }
- ).execute
-
- if result
- success
- else
- log_error(_("Could not save instance administration project ID, errors: %{errors}") % { errors: application_settings.errors.full_messages })
- error(_('Could not save project ID'))
- end
- end
-
- def add_group_members
- members = @group.add_users(group_maintainers, Gitlab::Access::MAINTAINER)
- errors = members.flat_map { |member| member.errors.full_messages }
-
- if errors.any?
- log_error("Could not add admins as members to self-monitoring project. Errors: #{errors}")
- error('Could not add admins as members')
- else
- success
- end
- end
-
- def add_to_whitelist
- return success unless prometheus_enabled?
- return success unless prometheus_listen_address.present?
-
- uri = parse_url(internal_prometheus_listen_address_uri)
- return error(_('Prometheus listen_address is not a valid URI')) unless uri
-
- result = ApplicationSettings::UpdateService.new(
- application_settings,
- group_owner,
- add_to_outbound_local_requests_whitelist: [uri.normalized_host]
- ).execute
-
- if result
- success
- else
- log_error(_("Could not add prometheus URL to whitelist, errors: %{errors}") % { errors: application_settings.errors.full_messages })
- error(_('Could not add prometheus URL to whitelist'))
- end
- end
-
- def add_prometheus_manual_configuration
- return success unless prometheus_enabled?
- return success unless prometheus_listen_address.present?
-
- service = project.find_or_initialize_service('prometheus')
-
- unless service.update(prometheus_service_attributes)
- log_error("Could not save prometheus manual configuration for self-monitoring project. Errors: #{service.errors.full_messages}")
- return error('Could not save prometheus manual configuration')
- end
-
- success
- end
-
- def application_settings
- strong_memoize(:application_settings) do
- Gitlab::CurrentSettings.expire_current_application_settings
- Gitlab::CurrentSettings.current_application_settings
- end
- end
-
- def project_created?
- application_settings.instance_administration_project.present?
- end
-
- def parse_url(uri_string)
- Addressable::URI.parse(uri_string)
- rescue Addressable::URI::InvalidURIError, TypeError
- end
-
- def prometheus_enabled?
- Gitlab.config.prometheus.enable
- rescue Settingslogic::MissingSetting
- false
- end
-
- def prometheus_listen_address
- Gitlab.config.prometheus.listen_address
- rescue Settingslogic::MissingSetting
- end
-
- def instance_admins
- @instance_admins ||= User.admins.active
- end
-
- def group_owner
- instance_admins.first
- end
-
- def group_maintainers
- # Exclude the first so that the group_owner is not added again as a member.
- instance_admins - [group_owner]
- end
-
- def create_group_params
- {
- name: GROUP_NAME,
- path: "#{GROUP_PATH}-#{SecureRandom.hex(4)}",
- visibility_level: VISIBILITY_LEVEL
- }
- end
-
- def create_project_params
- {
- initialize_with_readme: true,
- visibility_level: VISIBILITY_LEVEL,
- name: PROJECT_NAME,
- description: PROJECT_DESCRIPTION,
- namespace_id: @group.id
- }
- end
-
- def internal_prometheus_listen_address_uri
- if prometheus_listen_address.starts_with?('http')
- prometheus_listen_address
- else
- 'http://' + prometheus_listen_address
- end
- end
-
- def prometheus_service_attributes
- {
- api_url: internal_prometheus_listen_address_uri,
- manual_configuration: true,
- active: true
- }
- end
- end
- end
-end
diff --git a/app/views/ci/status/_icon.html.haml b/app/views/ci/status/_icon.html.haml
index 1249b98221f..fdaacb732c7 100644
--- a/app/views/ci/status/_icon.html.haml
+++ b/app/views/ci/status/_icon.html.haml
@@ -1,13 +1,10 @@
- status = local_assigns.fetch(:status)
- size = local_assigns.fetch(:size, 16)
-- type = local_assigns.fetch(:type, 'pipeline')
- tooltip_placement = local_assigns.fetch(:tooltip_placement, "left")
- path = local_assigns.fetch(:path, status.has_details? ? status.details_path : nil)
- option_css_classes = local_assigns.fetch(:option_css_classes, '')
- css_classes = "ci-status-link ci-status-icon ci-status-icon-#{status.group} has-tooltip #{option_css_classes}"
- title = s_("PipelineStatusTooltip|Pipeline: %{ci_status}") % {ci_status: status.label}
-- if type == 'commit'
- - title = s_("PipelineStatusTooltip|Commit: %{ci_status}") % {ci_status: status.label}
- if path
= link_to path, class: css_classes, title: title, data: { placement: tooltip_placement } do
diff --git a/app/views/layouts/_piwik.html.haml b/app/views/layouts/_piwik.html.haml
index 2cb2e23433d..361a7b03180 100644
--- a/app/views/layouts/_piwik.html.haml
+++ b/app/views/layouts/_piwik.html.haml
@@ -11,5 +11,5 @@
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
- <noscript><p><img src="//#{extra_config.piwik_url}/piwik.php?idsite=#{extra_config.piwik_site_id}" style="border:0;" alt="" /></p></noscript>
- <!-- End Piwik Code -->
+<noscript><p><img src="//#{extra_config.piwik_url}/piwik.php?idsite=#{extra_config.piwik_site_id}" style="border:0;" alt="" /></p></noscript>
+<!-- End Piwik Code -->
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index d99063e344f..0887e8e64da 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -47,7 +47,7 @@
= s_('Preferences|Layout width')
= f.select :layout, layout_choices, {}, class: 'select2'
.form-text.text-muted
- = s_('Preferences|Choose between fixed (max. 1280px) and fluid (100%%) application layout.')
+ = s_('Preferences|Choose between fixed (max. 1280px) and fluid (%{percentage}) application layout.').html_safe % { percentage: '100%' }
.form-group
= f.label :dashboard, class: 'label-bold' do
= s_('Preferences|Default dashboard')
diff --git a/app/views/projects/deployments/_deployment.html.haml b/app/views/projects/deployments/_deployment.html.haml
index a11e23b6daa..752be02443c 100644
--- a/app/views/projects/deployments/_deployment.html.haml
+++ b/app/views/projects/deployments/_deployment.html.haml
@@ -15,10 +15,10 @@
.flex-truncate-child
= link_to [@project.namespace.becomes(Namespace), @project, deployment.deployable], class: 'build-link' do
#{deployment.deployable.name} (##{deployment.deployable.id})
- - if deployment.user
+ - if deployment.deployed_by
%div
by
- = user_avatar(user: deployment.user, size: 20, css_class: "mr-0 float-none")
+ = user_avatar(user: deployment.deployed_by, size: 20, css_class: "mr-0 float-none")
.table-section.section-15{ role: 'gridcell' }
.table-mobile-header{ role: 'rowheader' }= _("Created")
diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml
index eb100e5cf47..6f8a93fbcf5 100644
--- a/app/views/projects/mirrors/_mirror_repos.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos.html.haml
@@ -13,8 +13,6 @@
.settings-content
= form_for @project, url: project_mirror_path(@project), html: { class: 'gl-show-field-errors js-mirror-form', autocomplete: 'new-password', data: mirrors_form_data_attributes } do |f|
.panel.panel-default
- .panel-heading
- %h3.panel-title= _('Mirror a repository')
.panel-body
%div= form_errors(@project)
diff --git a/app/views/projects/serverless/functions/index.html.haml b/app/views/projects/serverless/functions/index.html.haml
index 9c69aedfbfc..bac6c76684b 100644
--- a/app/views/projects/serverless/functions/index.html.haml
+++ b/app/views/projects/serverless/functions/index.html.haml
@@ -14,5 +14,5 @@
.js-serverless-functions-notice
.flash-container
- .top-area.adjust
+ .top-area.adjust.d-flex.justify-content-center
.serverless-functions-table#js-serverless-functions
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index aea09bf8d4d..837707707a9 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -139,7 +139,9 @@
- if signed_in
- if issuable_sidebar[:project_emails_disabled]
.block.js-emails-disabled
- = notification_description(:owner_disabled)
+ .sidebar-collapsed-icon.has-tooltip{ title: notification_description(:owner_disabled), data: { placement: "left", container: "body", boundary: 'viewport' } }
+ = notification_setting_icon
+ .hide-collapsed= notification_description(:owner_disabled)
- else
.js-sidebar-subscriptions-entry-point
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index b7474d891dc..573ed36d7f4 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -89,7 +89,7 @@
- if pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project)
- pipeline_path = pipelines_project_commit_path(project.pipeline_status.project, project.pipeline_status.sha, ref: project.pipeline_status.ref)
%span.icon-wrapper.pipeline-status
- = render 'ci/status/icon', status: project.commit.last_pipeline.detailed_status(current_user), type: 'commit', tooltip_placement: 'top', path: pipeline_path
+ = render 'ci/status/icon', status: project.commit.last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path
.updated-note
%span
= _('Updated')
diff --git a/changelogs/unreleased/21505-quickactions-update-pd.yml b/changelogs/unreleased/21505-quickactions-update-pd.yml
new file mode 100644
index 00000000000..243f8eda4e3
--- /dev/null
+++ b/changelogs/unreleased/21505-quickactions-update-pd.yml
@@ -0,0 +1,5 @@
+---
+title: Apply quickactions when modifying comments
+merge_request: 31136
+author:
+type: added
diff --git a/changelogs/unreleased/55360-redundant-index-in-the-releases-table_v2.yml b/changelogs/unreleased/55360-redundant-index-in-the-releases-table_v2.yml
new file mode 100644
index 00000000000..91a1fb5e6c9
--- /dev/null
+++ b/changelogs/unreleased/55360-redundant-index-in-the-releases-table_v2.yml
@@ -0,0 +1,5 @@
+---
+title: Removed redundant index on releases table
+merge_request: 31487
+author:
+type: removed
diff --git a/changelogs/unreleased/55999-misleading-pipeline-tooltip-messages-and-misleading-ci-status-icons.yml b/changelogs/unreleased/55999-misleading-pipeline-tooltip-messages-and-misleading-ci-status-icons.yml
new file mode 100644
index 00000000000..a937614be38
--- /dev/null
+++ b/changelogs/unreleased/55999-misleading-pipeline-tooltip-messages-and-misleading-ci-status-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Remove "Commit" from pipeline status tooltips
+merge_request: 31861
+author:
+type: fixed
diff --git a/changelogs/unreleased/56883-migration.yml b/changelogs/unreleased/56883-migration.yml
new file mode 100644
index 00000000000..d6eb49e62e1
--- /dev/null
+++ b/changelogs/unreleased/56883-migration.yml
@@ -0,0 +1,5 @@
+---
+title: Create a project for self-monitoring the GitLab instance
+merge_request: 31389
+author:
+type: added
diff --git a/changelogs/unreleased/63502-encrypt-deploy-token.yml b/changelogs/unreleased/63502-encrypt-deploy-token.yml
new file mode 100644
index 00000000000..81ce1e6c3dd
--- /dev/null
+++ b/changelogs/unreleased/63502-encrypt-deploy-token.yml
@@ -0,0 +1,5 @@
+---
+title: Encrypt existing and new deploy tokens
+merge_request: 30679
+author:
+type: other
diff --git a/changelogs/unreleased/64269-pipeline-api-fails-with-401.yml b/changelogs/unreleased/64269-pipeline-api-fails-with-401.yml
new file mode 100644
index 00000000000..582339901ae
--- /dev/null
+++ b/changelogs/unreleased/64269-pipeline-api-fails-with-401.yml
@@ -0,0 +1,5 @@
+---
+title: Read pipelines from public projects through API without an access token
+merge_request: 31816
+author:
+type: fixed
diff --git a/changelogs/unreleased/64764-fix-serverless-layout.yml b/changelogs/unreleased/64764-fix-serverless-layout.yml
new file mode 100644
index 00000000000..9717062df93
--- /dev/null
+++ b/changelogs/unreleased/64764-fix-serverless-layout.yml
@@ -0,0 +1,5 @@
+---
+title: Fix serverless entry page layout
+merge_request: 32029
+author:
+type: fixed
diff --git a/changelogs/unreleased/66037-deployment-user.yml b/changelogs/unreleased/66037-deployment-user.yml
new file mode 100644
index 00000000000..8a61b8145af
--- /dev/null
+++ b/changelogs/unreleased/66037-deployment-user.yml
@@ -0,0 +1,5 @@
+---
+title: Return correct user for manual deployments
+merge_request: 32004
+author:
+type: fixed
diff --git a/changelogs/unreleased/66073-use-time-series-chart-instead-of-area-chart-in-panel_types.yml b/changelogs/unreleased/66073-use-time-series-chart-instead-of-area-chart-in-panel_types.yml
new file mode 100644
index 00000000000..8d7af96a7d8
--- /dev/null
+++ b/changelogs/unreleased/66073-use-time-series-chart-instead-of-area-chart-in-panel_types.yml
@@ -0,0 +1,5 @@
+---
+title: Enable line charts in dashbaord panels and embedded charts
+merge_request: 31920
+author:
+type: added
diff --git a/changelogs/unreleased/66402-use-visual-review-tools-npm-package.yml b/changelogs/unreleased/66402-use-visual-review-tools-npm-package.yml
new file mode 100644
index 00000000000..46773e12002
--- /dev/null
+++ b/changelogs/unreleased/66402-use-visual-review-tools-npm-package.yml
@@ -0,0 +1,5 @@
+---
+title: Move visual review toolbar code to NPM
+merge_request: 32159
+author:
+type: fixed
diff --git a/changelogs/unreleased/66443-unrecoverable-configuration-loop-in-external-auth-control.yml b/changelogs/unreleased/66443-unrecoverable-configuration-loop-in-external-auth-control.yml
new file mode 100644
index 00000000000..ab52e3e5a2c
--- /dev/null
+++ b/changelogs/unreleased/66443-unrecoverable-configuration-loop-in-external-auth-control.yml
@@ -0,0 +1,5 @@
+---
+title: Don't check external authorization when disabling the service
+merge_request: 32102
+author: Robert Schilling
+type: fixed
diff --git a/changelogs/unreleased/fe-fix-issuable-sidebar-icon-of-notification-disabled.yml b/changelogs/unreleased/fe-fix-issuable-sidebar-icon-of-notification-disabled.yml
new file mode 100644
index 00000000000..736e12ff694
--- /dev/null
+++ b/changelogs/unreleased/fe-fix-issuable-sidebar-icon-of-notification-disabled.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issuable sidebar icon on notification disabled
+merge_request: 32134
+author:
+type: fixed
diff --git a/changelogs/unreleased/georgekoltsov-54023-fogbugz-visibility-level.yml b/changelogs/unreleased/georgekoltsov-54023-fogbugz-visibility-level.yml
new file mode 100644
index 00000000000..d292958c92a
--- /dev/null
+++ b/changelogs/unreleased/georgekoltsov-54023-fogbugz-visibility-level.yml
@@ -0,0 +1,5 @@
+---
+title: Change default visibility level for FogBugz imported projects to Private
+merge_request: 32142
+author:
+type: fixed
diff --git a/changelogs/unreleased/id-code-review-smau.yml b/changelogs/unreleased/id-code-review-smau.yml
new file mode 100644
index 00000000000..0bc7bca789b
--- /dev/null
+++ b/changelogs/unreleased/id-code-review-smau.yml
@@ -0,0 +1,5 @@
+---
+title: Add usage pings for merge request creating
+merge_request: 32059
+author:
+type: added
diff --git a/changelogs/unreleased/oauth_bypass_two_factor.yml b/changelogs/unreleased/oauth_bypass_two_factor.yml
new file mode 100644
index 00000000000..7261e65a9f3
--- /dev/null
+++ b/changelogs/unreleased/oauth_bypass_two_factor.yml
@@ -0,0 +1,5 @@
+---
+title: Add option to allow OAuth providers to bypass two factor
+merge_request: 31996
+author: Dodocat
+type: added
diff --git a/changelogs/unreleased/sh-fix-nplusone-issues.yml b/changelogs/unreleased/sh-fix-nplusone-issues.yml
new file mode 100644
index 00000000000..f749b5eeb40
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-nplusone-issues.yml
@@ -0,0 +1,5 @@
+---
+title: Fix N+1 Gitaly calls in /api/v4/projects/:id/issues
+merge_request: 32171
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-fix-piwik-template.yml b/changelogs/unreleased/sh-fix-piwik-template.yml
new file mode 100644
index 00000000000..f0baed6a2e0
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-piwik-template.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Piwik not working
+merge_request: 32234
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-guard-against-orphaned-project-feature.yml b/changelogs/unreleased/sh-guard-against-orphaned-project-feature.yml
new file mode 100644
index 00000000000..99c8732c5b0
--- /dev/null
+++ b/changelogs/unreleased/sh-guard-against-orphaned-project-feature.yml
@@ -0,0 +1,5 @@
+---
+title: Guard against deleted project feature entry in project permissions
+merge_request: 32187
+author:
+type: fixed
diff --git a/changelogs/unreleased/user_name_migration.yml b/changelogs/unreleased/user_name_migration.yml
new file mode 100644
index 00000000000..11d6ff2e8b2
--- /dev/null
+++ b/changelogs/unreleased/user_name_migration.yml
@@ -0,0 +1,5 @@
+---
+title: Add First and Last name columns to User model
+merge_request: 31985
+author:
+type: added
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 973c2747838..20b1020e025 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -780,6 +780,14 @@ production: &base
# (default: [])
external_providers: []
+ # CAUTION!
+ # This allows users to login with the specified providers without two factor. Define the allowed providers
+ # using an array, e.g. ["twitter", 'google_oauth2'], or as true/false to allow all providers or none.
+ # This option should only be configured for providers which already have two factor.
+ # This configration dose not apply to SAML.
+ # (default: false)
+ allow_bypass_two_factor: ["twitter", 'google_oauth2']
+
## Auth providers
# Uncomment the following lines and fill in the data of the auth provider you want to use
# If your favorite auth provider is not listed you can use others:
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index fdc6b0a05ab..81433b620bc 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -84,6 +84,7 @@ Settings['omniauth'] ||= Settingslogic.new({})
Settings.omniauth['enabled'] = true if Settings.omniauth['enabled'].nil?
Settings.omniauth['auto_sign_in_with_provider'] = false if Settings.omniauth['auto_sign_in_with_provider'].nil?
Settings.omniauth['allow_single_sign_on'] = false if Settings.omniauth['allow_single_sign_on'].nil?
+Settings.omniauth['allow_bypass_two_factor'] = false if Settings.omniauth['allow_bypass_two_factor'].nil?
Settings.omniauth['external_providers'] = [] if Settings.omniauth['external_providers'].nil?
Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block_auto_created_users'].nil?
Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil?
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 442b4b4c21e..969a84e85dd 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -298,6 +298,13 @@ module.exports = {
from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'),
to: path.join(ROOT_PATH, 'public/assets/webpack/cmaps/'),
},
+ {
+ from: path.join(
+ ROOT_PATH,
+ 'node_modules/@gitlab/visual-review-tools/dist/visual_review_toolbar.js',
+ ),
+ to: path.join(ROOT_PATH, 'public/assets/webpack'),
+ },
]),
// compression can require a lot of compute time and is disabled in CI
diff --git a/config/webpack.config.review_toolbar.js b/config/webpack.config.review_toolbar.js
deleted file mode 100644
index baaba7ed387..00000000000
--- a/config/webpack.config.review_toolbar.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const path = require('path');
-const CompressionPlugin = require('compression-webpack-plugin');
-
-const ROOT_PATH = path.resolve(__dirname, '..');
-const CACHE_PATH = process.env.WEBPACK_CACHE_PATH || path.join(ROOT_PATH, 'tmp/cache');
-const NO_SOURCEMAPS = process.env.NO_SOURCEMAPS;
-const IS_PRODUCTION = process.env.NODE_ENV === 'production';
-
-const devtool = IS_PRODUCTION ? 'source-map' : 'cheap-module-eval-source-map';
-
-const alias = {
- vendor: path.join(ROOT_PATH, 'vendor/assets/javascripts'),
- spec: path.join(ROOT_PATH, 'spec/javascripts'),
-};
-
-module.exports = {
- mode: IS_PRODUCTION ? 'production' : 'development',
-
- context: path.join(ROOT_PATH, 'app/assets/javascripts'),
-
- name: 'visual_review_toolbar',
-
- entry: './visual_review_toolbar',
-
- output: {
- path: path.join(ROOT_PATH, 'public/assets/webpack'),
- filename: 'visual_review_toolbar.js',
- library: 'VisualReviewToolbar',
- libraryTarget: 'var',
- },
-
- resolve: {
- alias,
- },
-
- module: {
- rules: [
- {
- test: /\.js$/,
- loader: 'babel-loader',
- options: {
- cacheDirectory: path.join(CACHE_PATH, 'babel-loader'),
- },
- },
- {
- test: /\.css$/,
- use: ['style-loader', 'css-loader'],
- },
- ],
- },
-
- plugins: [
- // compression can require a lot of compute time and is disabled in CI
- new CompressionPlugin(),
- ].filter(Boolean),
-
- devtool: NO_SOURCEMAPS ? false : devtool,
-};
diff --git a/danger/only_documentation/Dangerfile b/danger/only_documentation/Dangerfile
index dad12c0d29c..ce7ede26d9a 100644
--- a/danger/only_documentation/Dangerfile
+++ b/danger/only_documentation/Dangerfile
@@ -1,7 +1,7 @@
# rubocop:disable Style/SignalException
# frozen_string_literal: true
-has_only_docs_changes = helper.all_changed_files.all? { |file| file.start_with?('doc/', '.gitlab/ci/docs.gitlab-ci.yml', '.mdlrc') || file.end_with?('.md') }
+has_only_docs_changes = helper.all_changed_files.all? { |file| file.start_with?('doc/', '.gitlab/ci/docs.gitlab-ci.yml', '.markdownlint.json') || file.end_with?('.md') }
is_docs_only_branch = gitlab.branch_for_head =~ /(^docs[\/-].*|.*-docs$)/
if is_docs_only_branch && !has_only_docs_changes
diff --git a/db/migrate/20171230123729_init_schema.rb b/db/migrate/20171230123729_init_schema.rb
index fa90b37954f..a474ea2f925 100644
--- a/db/migrate/20171230123729_init_schema.rb
+++ b/db/migrate/20171230123729_init_schema.rb
@@ -5,6 +5,7 @@
# rubocop:disable Metrics/AbcSize
# rubocop:disable Migration/AddConcurrentForeignKey
# rubocop:disable Style/WordArray
+# rubocop:disable Migration/AddLimitToStringColumns
class InitSchema < ActiveRecord::Migration[4.2]
DOWNTIME = false
@@ -1852,3 +1853,4 @@ class InitSchema < ActiveRecord::Migration[4.2]
raise ActiveRecord::IrreversibleMigration, "The initial migration is not revertable"
end
end
+# rubocop:enable Migration/AddLimitToStringColumns
diff --git a/db/migrate/20180101160629_create_prometheus_metrics.rb b/db/migrate/20180101160629_create_prometheus_metrics.rb
index e3b1ed710d6..a098b999a0a 100644
--- a/db/migrate/20180101160629_create_prometheus_metrics.rb
+++ b/db/migrate/20180101160629_create_prometheus_metrics.rb
@@ -4,6 +4,7 @@ class CreatePrometheusMetrics < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :prometheus_metrics do |t|
t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: false
t.string :title, null: false
@@ -14,5 +15,6 @@ class CreatePrometheusMetrics < ActiveRecord::Migration[4.2]
t.integer :group, null: false, index: true
t.timestamps_with_timezone null: false
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180122162010_add_auto_devops_domain_to_application_settings.rb b/db/migrate/20180122162010_add_auto_devops_domain_to_application_settings.rb
index c76dc5b3a68..eb446ad0d72 100644
--- a/db/migrate/20180122162010_add_auto_devops_domain_to_application_settings.rb
+++ b/db/migrate/20180122162010_add_auto_devops_domain_to_application_settings.rb
@@ -8,6 +8,6 @@ class AddAutoDevopsDomainToApplicationSettings < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :application_settings, :auto_devops_domain, :string
+ add_column :application_settings, :auto_devops_domain, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180129193323_add_uploads_builder_context.rb b/db/migrate/20180129193323_add_uploads_builder_context.rb
index c7227bf0f1e..710fa7b3ba8 100644
--- a/db/migrate/20180129193323_add_uploads_builder_context.rb
+++ b/db/migrate/20180129193323_add_uploads_builder_context.rb
@@ -8,7 +8,9 @@ class AddUploadsBuilderContext < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
add_column :uploads, :mount_point, :string
add_column :uploads, :secret, :string
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180212030105_add_external_ip_to_clusters_applications_ingress.rb b/db/migrate/20180212030105_add_external_ip_to_clusters_applications_ingress.rb
index e2a9a68b1ad..78aa2014601 100644
--- a/db/migrate/20180212030105_add_external_ip_to_clusters_applications_ingress.rb
+++ b/db/migrate/20180212030105_add_external_ip_to_clusters_applications_ingress.rb
@@ -4,6 +4,6 @@ class AddExternalIpToClustersApplicationsIngress < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :clusters_applications_ingress, :external_ip, :string
+ add_column :clusters_applications_ingress, :external_ip, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180214093516_create_badges.rb b/db/migrate/20180214093516_create_badges.rb
index 66e017b115a..fe27d465571 100644
--- a/db/migrate/20180214093516_create_badges.rb
+++ b/db/migrate/20180214093516_create_badges.rb
@@ -2,6 +2,7 @@ class CreateBadges < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :badges do |t|
t.string :link_url, null: false
t.string :image_url, null: false
@@ -11,6 +12,7 @@ class CreateBadges < ActiveRecord::Migration[4.2]
t.timestamps_with_timezone null: false
end
+ # rubocop:enable Migration/AddLimitToStringColumns
# rubocop:disable Migration/AddConcurrentForeignKey
add_foreign_key :badges, :namespaces, column: :group_id, on_delete: :cascade
diff --git a/db/migrate/20180214155405_create_clusters_applications_runners.rb b/db/migrate/20180214155405_create_clusters_applications_runners.rb
index ce594c91890..f611fefbb0d 100644
--- a/db/migrate/20180214155405_create_clusters_applications_runners.rb
+++ b/db/migrate/20180214155405_create_clusters_applications_runners.rb
@@ -13,7 +13,7 @@ class CreateClustersApplicationsRunners < ActiveRecord::Migration[4.2]
t.index :cluster_id, unique: true
t.integer :status, null: false
t.timestamps_with_timezone null: false
- t.string :version, null: false
+ t.string :version, null: false # rubocop:disable Migration/AddLimitToStringColumns
t.text :status_reason
end
diff --git a/db/migrate/20180216120000_add_pages_domain_verification.rb b/db/migrate/20180216120000_add_pages_domain_verification.rb
index f709f5a5809..b2f19f2e1a9 100644
--- a/db/migrate/20180216120000_add_pages_domain_verification.rb
+++ b/db/migrate/20180216120000_add_pages_domain_verification.rb
@@ -3,6 +3,6 @@ class AddPagesDomainVerification < ActiveRecord::Migration[4.2]
def change
add_column :pages_domains, :verified_at, :datetime_with_timezone
- add_column :pages_domains, :verification_code, :string
+ add_column :pages_domains, :verification_code, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180222043024_add_ip_address_to_runner.rb b/db/migrate/20180222043024_add_ip_address_to_runner.rb
index b52366c0be1..08fb0bd900c 100644
--- a/db/migrate/20180222043024_add_ip_address_to_runner.rb
+++ b/db/migrate/20180222043024_add_ip_address_to_runner.rb
@@ -4,6 +4,6 @@ class AddIpAddressToRunner < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :ci_runners, :ip_address, :string
+ add_column :ci_runners, :ip_address, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180308125206_add_user_internal_regex_to_application_setting.rb b/db/migrate/20180308125206_add_user_internal_regex_to_application_setting.rb
index 5e4bf96f86f..9bdd44baf58 100644
--- a/db/migrate/20180308125206_add_user_internal_regex_to_application_setting.rb
+++ b/db/migrate/20180308125206_add_user_internal_regex_to_application_setting.rb
@@ -4,7 +4,7 @@ class AddUserInternalRegexToApplicationSetting < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
- add_column :application_settings, :user_default_internal_regex, :string, null: true
+ add_column :application_settings, :user_default_internal_regex, :string, null: true # rubocop:disable Migration/AddLimitToStringColumns
end
def down
diff --git a/db/migrate/20180315160435_add_external_auth_mutual_tls_fields_to_project_settings.rb b/db/migrate/20180315160435_add_external_auth_mutual_tls_fields_to_project_settings.rb
index ee3d1078f5e..c379d207ff0 100644
--- a/db/migrate/20180315160435_add_external_auth_mutual_tls_fields_to_project_settings.rb
+++ b/db/migrate/20180315160435_add_external_auth_mutual_tls_fields_to_project_settings.rb
@@ -2,6 +2,7 @@ class AddExternalAuthMutualTlsFieldsToProjectSettings < ActiveRecord::Migration[
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
add_column :application_settings,
:external_auth_client_cert, :text
add_column :application_settings,
@@ -12,5 +13,6 @@ class AddExternalAuthMutualTlsFieldsToProjectSettings < ActiveRecord::Migration[
:encrypted_external_auth_client_key_pass, :string
add_column :application_settings,
:encrypted_external_auth_client_key_pass_iv, :string
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180319190020_create_deploy_tokens.rb b/db/migrate/20180319190020_create_deploy_tokens.rb
index a4d797679c5..f444521b3ae 100644
--- a/db/migrate/20180319190020_create_deploy_tokens.rb
+++ b/db/migrate/20180319190020_create_deploy_tokens.rb
@@ -2,6 +2,7 @@ class CreateDeployTokens < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :deploy_tokens do |t|
t.boolean :revoked, default: false
t.boolean :read_repository, null: false, default: false
@@ -15,5 +16,6 @@ class CreateDeployTokens < ActiveRecord::Migration[4.2]
t.index [:token, :expires_at, :id], where: "(revoked IS FALSE)"
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180502122856_create_project_mirror_data.rb b/db/migrate/20180502122856_create_project_mirror_data.rb
index 9781815a97b..04367e1c98b 100644
--- a/db/migrate/20180502122856_create_project_mirror_data.rb
+++ b/db/migrate/20180502122856_create_project_mirror_data.rb
@@ -3,6 +3,7 @@ class CreateProjectMirrorData < ActiveRecord::Migration[4.2]
DOWNTIME = false
+ # rubocop:disable Migration/AddLimitToStringColumns
def up
if table_exists?(:project_mirror_data)
add_column :project_mirror_data, :status, :string unless column_exists?(:project_mirror_data, :status)
@@ -17,6 +18,7 @@ class CreateProjectMirrorData < ActiveRecord::Migration[4.2]
end
end
end
+ # rubocop:enable Migration/AddLimitToStringColumns
def down
remove_column :project_mirror_data, :status
diff --git a/db/migrate/20180503131624_create_remote_mirrors.rb b/db/migrate/20180503131624_create_remote_mirrors.rb
index 288ae365f0f..a079c1b3328 100644
--- a/db/migrate/20180503131624_create_remote_mirrors.rb
+++ b/db/migrate/20180503131624_create_remote_mirrors.rb
@@ -5,6 +5,7 @@ class CreateRemoteMirrors < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
+ # rubocop:disable Migration/AddLimitToStringColumns
def up
return if table_exists?(:remote_mirrors)
@@ -27,6 +28,7 @@ class CreateRemoteMirrors < ActiveRecord::Migration[4.2]
t.timestamps null: false
end
end
+ # rubocop:enable Migration/AddLimitToStringColumns
def down
# ee/db/migrate/20160321161032_create_remote_mirrors_ee.rb will remove the table
diff --git a/db/migrate/20180503175053_ensure_missing_columns_to_project_mirror_data.rb b/db/migrate/20180503175053_ensure_missing_columns_to_project_mirror_data.rb
index 3775b3a08c9..f00493ed515 100644
--- a/db/migrate/20180503175053_ensure_missing_columns_to_project_mirror_data.rb
+++ b/db/migrate/20180503175053_ensure_missing_columns_to_project_mirror_data.rb
@@ -4,8 +4,8 @@ class EnsureMissingColumnsToProjectMirrorData < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
- add_column :project_mirror_data, :status, :string unless column_exists?(:project_mirror_data, :status)
- add_column :project_mirror_data, :jid, :string unless column_exists?(:project_mirror_data, :jid)
+ add_column :project_mirror_data, :status, :string unless column_exists?(:project_mirror_data, :status) # rubocop:disable Migration/AddLimitToStringColumns
+ add_column :project_mirror_data, :jid, :string unless column_exists?(:project_mirror_data, :jid) # rubocop:disable Migration/AddLimitToStringColumns
add_column :project_mirror_data, :last_error, :text unless column_exists?(:project_mirror_data, :last_error)
end
diff --git a/db/migrate/20180511131058_create_clusters_applications_jupyter.rb b/db/migrate/20180511131058_create_clusters_applications_jupyter.rb
index 749aeeb4792..4633d930e2d 100644
--- a/db/migrate/20180511131058_create_clusters_applications_jupyter.rb
+++ b/db/migrate/20180511131058_create_clusters_applications_jupyter.rb
@@ -7,17 +7,19 @@ class CreateClustersApplicationsJupyter < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :clusters_applications_jupyter do |t|
t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
t.references :oauth_application, foreign_key: { on_delete: :nullify }
t.integer :status, null: false
- t.string :version, null: false
- t.string :hostname
+ t.string :version, null: false # rubocop:disable Migration/AddLimitToStringColumns
+ t.string :hostname # rubocop:disable Migration/AddLimitToStringColumns
t.timestamps_with_timezone null: false
t.text :status_reason
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180515121227_create_notes_diff_files.rb b/db/migrate/20180515121227_create_notes_diff_files.rb
index e50324d8599..5f6dba11ff9 100644
--- a/db/migrate/20180515121227_create_notes_diff_files.rb
+++ b/db/migrate/20180515121227_create_notes_diff_files.rb
@@ -4,6 +4,7 @@ class CreateNotesDiffFiles < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :note_diff_files do |t|
t.references :diff_note, references: :notes, null: false, index: { unique: true }
t.text :diff, null: false
@@ -18,5 +19,6 @@ class CreateNotesDiffFiles < ActiveRecord::Migration[4.2]
# rubocop:disable Migration/AddConcurrentForeignKey
add_foreign_key :note_diff_files, :notes, column: :diff_note_id, on_delete: :cascade
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180529093006_ensure_remote_mirror_columns.rb b/db/migrate/20180529093006_ensure_remote_mirror_columns.rb
index 207e1f089fb..a0a1150f022 100644
--- a/db/migrate/20180529093006_ensure_remote_mirror_columns.rb
+++ b/db/migrate/20180529093006_ensure_remote_mirror_columns.rb
@@ -8,7 +8,7 @@ class EnsureRemoteMirrorColumns < ActiveRecord::Migration[4.2]
def up
# rubocop:disable Migration/Datetime
add_column :remote_mirrors, :last_update_started_at, :datetime unless column_exists?(:remote_mirrors, :last_update_started_at)
- add_column :remote_mirrors, :remote_name, :string unless column_exists?(:remote_mirrors, :remote_name)
+ add_column :remote_mirrors, :remote_name, :string unless column_exists?(:remote_mirrors, :remote_name) # rubocop:disable Migration/AddLimitToStringColumns
unless column_exists?(:remote_mirrors, :only_protected_branches)
add_column_with_default(:remote_mirrors,
diff --git a/db/migrate/20180531185349_add_repository_languages.rb b/db/migrate/20180531185349_add_repository_languages.rb
index 26a01c3bb26..d517c21c26c 100644
--- a/db/migrate/20180531185349_add_repository_languages.rb
+++ b/db/migrate/20180531185349_add_repository_languages.rb
@@ -4,6 +4,7 @@ class AddRepositoryLanguages < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table(:programming_languages) do |t|
t.string :name, null: false
t.string :color, null: false
@@ -19,6 +20,7 @@ class AddRepositoryLanguages < ActiveRecord::Migration[4.2]
add_index :programming_languages, :name, unique: true
add_index :repository_languages, [:project_id, :programming_language_id],
unique: true, name: "index_repository_languages_on_project_and_languages_id"
+ # rubocop:enable Migration/AddLimitToStringColumns
end
def down
diff --git a/db/migrate/20180613081317_create_ci_builds_runner_session.rb b/db/migrate/20180613081317_create_ci_builds_runner_session.rb
index eb41f76b105..68af38834d2 100644
--- a/db/migrate/20180613081317_create_ci_builds_runner_session.rb
+++ b/db/migrate/20180613081317_create_ci_builds_runner_session.rb
@@ -8,6 +8,7 @@ class CreateCiBuildsRunnerSession < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :ci_builds_runner_session, id: :bigserial do |t|
t.integer :build_id, null: false
t.string :url, null: false
@@ -17,5 +18,6 @@ class CreateCiBuildsRunnerSession < ActiveRecord::Migration[4.2]
t.foreign_key :ci_builds, column: :build_id, on_delete: :cascade
t.index :build_id, unique: true
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180713092803_create_user_statuses.rb b/db/migrate/20180713092803_create_user_statuses.rb
index 43b96805c1e..3abab4e45a9 100644
--- a/db/migrate/20180713092803_create_user_statuses.rb
+++ b/db/migrate/20180713092803_create_user_statuses.rb
@@ -6,6 +6,7 @@ class CreateUserStatuses < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :user_statuses, id: false, primary_key: :user_id do |t|
t.references :user,
foreign_key: { on_delete: :cascade },
@@ -16,5 +17,6 @@ class CreateUserStatuses < ActiveRecord::Migration[4.2]
t.string :message, limit: 100
t.string :message_html
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180814153625_add_commit_email_to_users.rb b/db/migrate/20180814153625_add_commit_email_to_users.rb
index 4d9217ea504..98bafc14a03 100644
--- a/db/migrate/20180814153625_add_commit_email_to_users.rb
+++ b/db/migrate/20180814153625_add_commit_email_to_users.rb
@@ -28,6 +28,6 @@ class AddCommitEmailToUsers < ActiveRecord::Migration[4.2]
# disable_ddl_transaction!
def change
- add_column :users, :commit_email, :string
+ add_column :users, :commit_email, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180831164908_add_identifier_to_prometheus_metric.rb b/db/migrate/20180831164908_add_identifier_to_prometheus_metric.rb
index 7aa5950249c..8f30363c310 100644
--- a/db/migrate/20180831164908_add_identifier_to_prometheus_metric.rb
+++ b/db/migrate/20180831164908_add_identifier_to_prometheus_metric.rb
@@ -6,6 +6,6 @@ class AddIdentifierToPrometheusMetric < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :prometheus_metrics, :identifier, :string
+ add_column :prometheus_metrics, :identifier, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180910115836_add_attr_encrypted_columns_to_web_hook.rb b/db/migrate/20180910115836_add_attr_encrypted_columns_to_web_hook.rb
index ca8dbdba2bb..9757f7fdc79 100644
--- a/db/migrate/20180910115836_add_attr_encrypted_columns_to_web_hook.rb
+++ b/db/migrate/20180910115836_add_attr_encrypted_columns_to_web_hook.rb
@@ -6,10 +6,12 @@ class AddAttrEncryptedColumnsToWebHook < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
add_column :web_hooks, :encrypted_token, :string
add_column :web_hooks, :encrypted_token_iv, :string
add_column :web_hooks, :encrypted_url, :string
add_column :web_hooks, :encrypted_url_iv, :string
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20180910153412_add_token_digest_to_personal_access_tokens.rb b/db/migrate/20180910153412_add_token_digest_to_personal_access_tokens.rb
index 142e454832f..52923f52499 100644
--- a/db/migrate/20180910153412_add_token_digest_to_personal_access_tokens.rb
+++ b/db/migrate/20180910153412_add_token_digest_to_personal_access_tokens.rb
@@ -8,7 +8,7 @@ class AddTokenDigestToPersonalAccessTokens < ActiveRecord::Migration[4.2]
def up
change_column :personal_access_tokens, :token, :string, null: true
- add_column :personal_access_tokens, :token_digest, :string
+ add_column :personal_access_tokens, :token_digest, :string # rubocop:disable Migration/AddLimitToStringColumns
end
def down
diff --git a/db/migrate/20180912111628_add_knative_application.rb b/db/migrate/20180912111628_add_knative_application.rb
index 86d9100d2e7..7c55de02d1c 100644
--- a/db/migrate/20180912111628_add_knative_application.rb
+++ b/db/migrate/20180912111628_add_knative_application.rb
@@ -6,6 +6,7 @@ class AddKnativeApplication < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table "clusters_applications_knative" do |t|
t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
@@ -16,5 +17,6 @@ class AddKnativeApplication < ActiveRecord::Migration[4.2]
t.string "hostname"
t.text "status_reason"
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181009190428_create_clusters_kubernetes_namespaces.rb b/db/migrate/20181009190428_create_clusters_kubernetes_namespaces.rb
index 62ad6c63d0a..b6ffb2866aa 100644
--- a/db/migrate/20181009190428_create_clusters_kubernetes_namespaces.rb
+++ b/db/migrate/20181009190428_create_clusters_kubernetes_namespaces.rb
@@ -5,6 +5,7 @@ class CreateClustersKubernetesNamespaces < ActiveRecord::Migration[4.2]
INDEX_NAME = 'kubernetes_namespaces_cluster_and_namespace'
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :clusters_kubernetes_namespaces, id: :bigserial do |t|
t.references :cluster, null: false, index: true, foreign_key: { on_delete: :cascade }
t.references :project, index: true, foreign_key: { on_delete: :nullify }
@@ -20,5 +21,6 @@ class CreateClustersKubernetesNamespaces < ActiveRecord::Migration[4.2]
t.index [:cluster_id, :namespace], name: INDEX_NAME, unique: true
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181019032400_add_shards_table.rb b/db/migrate/20181019032400_add_shards_table.rb
index e31af97cc94..82287e5c3b5 100644
--- a/db/migrate/20181019032400_add_shards_table.rb
+++ b/db/migrate/20181019032400_add_shards_table.rb
@@ -5,7 +5,7 @@ class AddShardsTable < ActiveRecord::Migration[4.2]
def change
create_table :shards do |t|
- t.string :name, null: false, index: { unique: true }
+ t.string :name, null: false, index: { unique: true } # rubocop:disable Migration/AddLimitToStringColumns
end
end
end
diff --git a/db/migrate/20181019032408_add_repositories_table.rb b/db/migrate/20181019032408_add_repositories_table.rb
index 2153c1c9fc6..dd510b44084 100644
--- a/db/migrate/20181019032408_add_repositories_table.rb
+++ b/db/migrate/20181019032408_add_repositories_table.rb
@@ -6,7 +6,7 @@ class AddRepositoriesTable < ActiveRecord::Migration[4.2]
def change
create_table :repositories, id: :bigserial do |t|
t.references :shard, null: false, index: true, foreign_key: { on_delete: :restrict }
- t.string :disk_path, null: false, index: { unique: true }
+ t.string :disk_path, null: false, index: { unique: true } # rubocop:disable Migration/AddLimitToStringColumns
end
add_column :projects, :pool_repository_id, :bigint
diff --git a/db/migrate/20181025115728_add_private_commit_email_hostname_to_application_settings.rb b/db/migrate/20181025115728_add_private_commit_email_hostname_to_application_settings.rb
index 052a344f182..c0e4897b8d7 100644
--- a/db/migrate/20181025115728_add_private_commit_email_hostname_to_application_settings.rb
+++ b/db/migrate/20181025115728_add_private_commit_email_hostname_to_application_settings.rb
@@ -6,6 +6,6 @@ class AddPrivateCommitEmailHostnameToApplicationSettings < ActiveRecord::Migrati
DOWNTIME = false
def change
- add_column(:application_settings, :commit_email_hostname, :string, null: true)
+ add_column(:application_settings, :commit_email_hostname, :string, null: true) # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181031190559_drop_gcp_clusters_table.rb b/db/migrate/20181031190559_drop_gcp_clusters_table.rb
index 597fe49f4c8..850fa93c75a 100644
--- a/db/migrate/20181031190559_drop_gcp_clusters_table.rb
+++ b/db/migrate/20181031190559_drop_gcp_clusters_table.rb
@@ -10,6 +10,7 @@ class DropGcpClustersTable < ActiveRecord::Migration[4.2]
end
def down
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :gcp_clusters do |t|
# Order columns by best align scheme
t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
@@ -49,5 +50,6 @@ class DropGcpClustersTable < ActiveRecord::Migration[4.2]
t.text :encrypted_gcp_token
t.string :encrypted_gcp_token_iv
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181101191341_create_clusters_applications_cert_manager.rb b/db/migrate/20181101191341_create_clusters_applications_cert_manager.rb
index 0b6155356d9..3bc20046311 100644
--- a/db/migrate/20181101191341_create_clusters_applications_cert_manager.rb
+++ b/db/migrate/20181101191341_create_clusters_applications_cert_manager.rb
@@ -6,6 +6,7 @@ class CreateClustersApplicationsCertManager < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :clusters_applications_cert_managers do |t|
t.references :cluster, null: false, index: false, foreign_key: { on_delete: :cascade }
t.integer :status, null: false
@@ -15,5 +16,6 @@ class CreateClustersApplicationsCertManager < ActiveRecord::Migration[4.2]
t.text :status_reason
t.index :cluster_id, unique: true
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181115140140_add_encrypted_runners_token_to_settings.rb b/db/migrate/20181115140140_add_encrypted_runners_token_to_settings.rb
index 5b2bb4f6b08..124eedf7933 100644
--- a/db/migrate/20181115140140_add_encrypted_runners_token_to_settings.rb
+++ b/db/migrate/20181115140140_add_encrypted_runners_token_to_settings.rb
@@ -6,6 +6,6 @@ class AddEncryptedRunnersTokenToSettings < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :application_settings, :runners_registration_token_encrypted, :string
+ add_column :application_settings, :runners_registration_token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181116050532_knative_external_ip.rb b/db/migrate/20181116050532_knative_external_ip.rb
index 5645b040a23..4634b411108 100644
--- a/db/migrate/20181116050532_knative_external_ip.rb
+++ b/db/migrate/20181116050532_knative_external_ip.rb
@@ -9,6 +9,6 @@ class KnativeExternalIp < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :clusters_applications_knative, :external_ip, :string
+ add_column :clusters_applications_knative, :external_ip, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181116141415_add_encrypted_runners_token_to_namespaces.rb b/db/migrate/20181116141415_add_encrypted_runners_token_to_namespaces.rb
index dcf565cd6c0..0a8ed912891 100644
--- a/db/migrate/20181116141415_add_encrypted_runners_token_to_namespaces.rb
+++ b/db/migrate/20181116141415_add_encrypted_runners_token_to_namespaces.rb
@@ -6,6 +6,6 @@ class AddEncryptedRunnersTokenToNamespaces < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :namespaces, :runners_token_encrypted, :string
+ add_column :namespaces, :runners_token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb b/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb
index 13cd80e5c8b..3083dff49b8 100644
--- a/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb
+++ b/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb
@@ -6,6 +6,6 @@ class AddEncryptedRunnersTokenToProjects < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :projects, :runners_token_encrypted, :string
+ add_column :projects, :runners_token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181120151656_add_token_encrypted_to_ci_runners.rb b/db/migrate/20181120151656_add_token_encrypted_to_ci_runners.rb
index 8b990451adc..2270246dfb4 100644
--- a/db/migrate/20181120151656_add_token_encrypted_to_ci_runners.rb
+++ b/db/migrate/20181120151656_add_token_encrypted_to_ci_runners.rb
@@ -6,6 +6,6 @@ class AddTokenEncryptedToCiRunners < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
- add_column :ci_runners, :token_encrypted, :string
+ add_column :ci_runners, :token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181122160027_create_project_repositories.rb b/db/migrate/20181122160027_create_project_repositories.rb
index e42cef9b1c6..3f123daa150 100644
--- a/db/migrate/20181122160027_create_project_repositories.rb
+++ b/db/migrate/20181122160027_create_project_repositories.rb
@@ -11,7 +11,7 @@ class CreateProjectRepositories < ActiveRecord::Migration[5.0]
def change
create_table :project_repositories, id: :bigserial do |t|
t.references :shard, null: false, index: true, foreign_key: { on_delete: :restrict }
- t.string :disk_path, null: false, index: { unique: true }
+ t.string :disk_path, null: false, index: { unique: true } # rubocop:disable Migration/AddLimitToStringColumns
t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
end
end
diff --git a/db/migrate/20181123144235_create_suggestions.rb b/db/migrate/20181123144235_create_suggestions.rb
index 1723f6de7eb..78888517db5 100644
--- a/db/migrate/20181123144235_create_suggestions.rb
+++ b/db/migrate/20181123144235_create_suggestions.rb
@@ -8,7 +8,7 @@ class CreateSuggestions < ActiveRecord::Migration[5.0]
t.references :note, foreign_key: { on_delete: :cascade }, null: false
t.integer :relative_order, null: false, limit: 2
t.boolean :applied, null: false, default: false
- t.string :commit_id
+ t.string :commit_id # rubocop:disable Migration/AddLimitToStringColumns
t.text :from_content, null: false
t.text :to_content, null: false
diff --git a/db/migrate/20181128123704_add_state_to_pool_repository.rb b/db/migrate/20181128123704_add_state_to_pool_repository.rb
index 714232ede56..04bbcf24f62 100644
--- a/db/migrate/20181128123704_add_state_to_pool_repository.rb
+++ b/db/migrate/20181128123704_add_state_to_pool_repository.rb
@@ -9,7 +9,7 @@ class AddStateToPoolRepository < ActiveRecord::Migration[5.0]
# the transactions don't have to be disabled
# rubocop: disable Migration/AddConcurrentForeignKey, Migration/AddIndex
def change
- add_column(:pool_repositories, :state, :string, null: true)
+ add_column(:pool_repositories, :state, :string, null: true) # rubocop:disable Migration/AddLimitToStringColumns
add_column :pool_repositories, :source_project_id, :integer
add_index :pool_repositories, :source_project_id, unique: true
diff --git a/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb b/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb
index 11b98203793..62a7421eae0 100644
--- a/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb
+++ b/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb
@@ -6,6 +6,6 @@ class AddTokenEncryptedToCiBuilds < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
- add_column :ci_builds, :token_encrypted, :string
+ add_column :ci_builds, :token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181203002526_add_project_bfg_object_map_column.rb b/db/migrate/20181203002526_add_project_bfg_object_map_column.rb
index 8b42cd6f941..5e6d416895c 100644
--- a/db/migrate/20181203002526_add_project_bfg_object_map_column.rb
+++ b/db/migrate/20181203002526_add_project_bfg_object_map_column.rb
@@ -4,6 +4,6 @@ class AddProjectBfgObjectMapColumn < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
- add_column :projects, :bfg_object_map, :string
+ add_column :projects, :bfg_object_map, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181211092510_add_name_author_id_and_sha_to_releases.rb b/db/migrate/20181211092510_add_name_author_id_and_sha_to_releases.rb
index 60815e0c31a..3ab808ba667 100644
--- a/db/migrate/20181211092510_add_name_author_id_and_sha_to_releases.rb
+++ b/db/migrate/20181211092510_add_name_author_id_and_sha_to_releases.rb
@@ -7,7 +7,7 @@ class AddNameAuthorIdAndShaToReleases < ActiveRecord::Migration[5.0]
def change
add_column :releases, :author_id, :integer
- add_column :releases, :name, :string
- add_column :releases, :sha, :string
+ add_column :releases, :name, :string # rubocop:disable Migration/AddLimitToStringColumns
+ add_column :releases, :sha, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181212171634_create_error_tracking_settings.rb b/db/migrate/20181212171634_create_error_tracking_settings.rb
index 18c38bd2c47..950b9a88005 100644
--- a/db/migrate/20181212171634_create_error_tracking_settings.rb
+++ b/db/migrate/20181212171634_create_error_tracking_settings.rb
@@ -6,6 +6,7 @@ class CreateErrorTrackingSettings < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :project_error_tracking_settings, id: :int, primary_key: :project_id, default: nil do |t|
t.boolean :enabled, null: false, default: true
t.string :api_url, null: false
@@ -13,5 +14,6 @@ class CreateErrorTrackingSettings < ActiveRecord::Migration[5.0]
t.string :encrypted_token_iv
t.foreign_key :projects, column: :project_id, on_delete: :cascade
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20181228175414_create_releases_link_table.rb b/db/migrate/20181228175414_create_releases_link_table.rb
index 03558202137..168c4722cc1 100644
--- a/db/migrate/20181228175414_create_releases_link_table.rb
+++ b/db/migrate/20181228175414_create_releases_link_table.rb
@@ -6,6 +6,7 @@ class CreateReleasesLinkTable < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :release_links, id: :bigserial do |t|
t.references :release, null: false, index: false, foreign_key: { on_delete: :cascade }
t.string :url, null: false
@@ -15,5 +16,6 @@ class CreateReleasesLinkTable < ActiveRecord::Migration[5.0]
t.index [:release_id, :url], unique: true
t.index [:release_id, :name], unique: true
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190109153125_add_merge_request_external_diffs.rb b/db/migrate/20190109153125_add_merge_request_external_diffs.rb
index c67903c7f67..a680856a3d8 100644
--- a/db/migrate/20190109153125_add_merge_request_external_diffs.rb
+++ b/db/migrate/20190109153125_add_merge_request_external_diffs.rb
@@ -11,7 +11,7 @@ class AddMergeRequestExternalDiffs < ActiveRecord::Migration[5.0]
def change
# Allow the merge request diff to store details about an external file
- add_column :merge_request_diffs, :external_diff, :string
+ add_column :merge_request_diffs, :external_diff, :string # rubocop:disable Migration/AddLimitToStringColumns
add_column :merge_request_diffs, :external_diff_store, :integer
add_column :merge_request_diffs, :stored_externally, :boolean
diff --git a/db/migrate/20190114172110_add_domain_to_cluster.rb b/db/migrate/20190114172110_add_domain_to_cluster.rb
index 58d7664b8c0..d8f10af9cad 100644
--- a/db/migrate/20190114172110_add_domain_to_cluster.rb
+++ b/db/migrate/20190114172110_add_domain_to_cluster.rb
@@ -4,6 +4,6 @@ class AddDomainToCluster < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
- add_column :clusters, :domain, :string
+ add_column :clusters, :domain, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190115092821_add_columns_project_error_tracking_settings.rb b/db/migrate/20190115092821_add_columns_project_error_tracking_settings.rb
index 190b6f958fd..afed929cce4 100644
--- a/db/migrate/20190115092821_add_columns_project_error_tracking_settings.rb
+++ b/db/migrate/20190115092821_add_columns_project_error_tracking_settings.rb
@@ -6,8 +6,8 @@ class AddColumnsProjectErrorTrackingSettings < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
- add_column :project_error_tracking_settings, :project_name, :string
- add_column :project_error_tracking_settings, :organization_name, :string
+ add_column :project_error_tracking_settings, :project_name, :string # rubocop:disable Migration/AddLimitToStringColumns
+ add_column :project_error_tracking_settings, :organization_name, :string # rubocop:disable Migration/AddLimitToStringColumns
change_column_default :project_error_tracking_settings, :enabled, from: true, to: false
diff --git a/db/migrate/20190116234221_add_sorting_fields_to_user_preference.rb b/db/migrate/20190116234221_add_sorting_fields_to_user_preference.rb
index 7bf581fe9b0..39aab600546 100644
--- a/db/migrate/20190116234221_add_sorting_fields_to_user_preference.rb
+++ b/db/migrate/20190116234221_add_sorting_fields_to_user_preference.rb
@@ -10,8 +10,8 @@ class AddSortingFieldsToUserPreference < ActiveRecord::Migration[5.0]
DOWNTIME = false
def up
- add_column :user_preferences, :issues_sort, :string
- add_column :user_preferences, :merge_requests_sort, :string
+ add_column :user_preferences, :issues_sort, :string # rubocop:disable Migration/AddLimitToStringColumns
+ add_column :user_preferences, :merge_requests_sort, :string # rubocop:disable Migration/AddLimitToStringColumns
end
def down
diff --git a/db/migrate/20190301182457_add_external_hostname_to_ingress_and_knative.rb b/db/migrate/20190301182457_add_external_hostname_to_ingress_and_knative.rb
index 2c3a54b12a9..37ba1090cf0 100644
--- a/db/migrate/20190301182457_add_external_hostname_to_ingress_and_knative.rb
+++ b/db/migrate/20190301182457_add_external_hostname_to_ingress_and_knative.rb
@@ -4,7 +4,7 @@ class AddExternalHostnameToIngressAndKnative < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
- add_column :clusters_applications_ingress, :external_hostname, :string
- add_column :clusters_applications_knative, :external_hostname, :string
+ add_column :clusters_applications_ingress, :external_hostname, :string # rubocop:disable Migration/AddLimitToStringColumns
+ add_column :clusters_applications_knative, :external_hostname, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190320174702_add_lets_encrypt_notification_email_to_application_settings.rb b/db/migrate/20190320174702_add_lets_encrypt_notification_email_to_application_settings.rb
index e9cf2af84a5..aeabf4e3cb4 100644
--- a/db/migrate/20190320174702_add_lets_encrypt_notification_email_to_application_settings.rb
+++ b/db/migrate/20190320174702_add_lets_encrypt_notification_email_to_application_settings.rb
@@ -10,6 +10,6 @@ class AddLetsEncryptNotificationEmailToApplicationSettings < ActiveRecord::Migra
DOWNTIME = false
def change
- add_column :application_settings, :lets_encrypt_notification_email, :string
+ add_column :application_settings, :lets_encrypt_notification_email, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190325105715_add_fields_to_user_preferences.rb b/db/migrate/20190325105715_add_fields_to_user_preferences.rb
index 9ea3b4f9cd8..4da5c496147 100644
--- a/db/migrate/20190325105715_add_fields_to_user_preferences.rb
+++ b/db/migrate/20190325105715_add_fields_to_user_preferences.rb
@@ -11,7 +11,7 @@ class AddFieldsToUserPreferences < ActiveRecord::Migration[5.0]
DOWNTIME = false
def up
- add_column(:user_preferences, :timezone, :string)
+ add_column(:user_preferences, :timezone, :string) # rubocop:disable Migration/AddLimitToStringColumns
add_column(:user_preferences, :time_display_relative, :boolean)
add_column(:user_preferences, :time_format_in_24h, :boolean)
end
diff --git a/db/migrate/20190327163904_add_notification_email_to_notification_settings.rb b/db/migrate/20190327163904_add_notification_email_to_notification_settings.rb
index 2f3069032a1..d912f922510 100644
--- a/db/migrate/20190327163904_add_notification_email_to_notification_settings.rb
+++ b/db/migrate/20190327163904_add_notification_email_to_notification_settings.rb
@@ -6,6 +6,6 @@ class AddNotificationEmailToNotificationSettings < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
- add_column :notification_settings, :notification_email, :string
+ add_column :notification_settings, :notification_email, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190402150158_backport_enterprise_schema.rb b/db/migrate/20190402150158_backport_enterprise_schema.rb
index 8762cc53ed7..3f13b68c2f3 100644
--- a/db/migrate/20190402150158_backport_enterprise_schema.rb
+++ b/db/migrate/20190402150158_backport_enterprise_schema.rb
@@ -2,6 +2,7 @@
# rubocop: disable Metrics/AbcSize
# rubocop: disable Migration/Datetime
+# rubocop: disable Migration/AddLimitToStringColumns
class BackportEnterpriseSchema < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
@@ -2190,3 +2191,4 @@ class BackportEnterpriseSchema < ActiveRecord::Migration[5.0]
end
# rubocop: enable Metrics/AbcSize
# rubocop: enable Migration/Datetime
+# rubocop: enable Migration/AddLimitToStringColumns
diff --git a/db/migrate/20190409224933_add_name_to_geo_nodes.rb b/db/migrate/20190409224933_add_name_to_geo_nodes.rb
index 2dff81b429c..65c01683995 100644
--- a/db/migrate/20190409224933_add_name_to_geo_nodes.rb
+++ b/db/migrate/20190409224933_add_name_to_geo_nodes.rb
@@ -10,7 +10,7 @@ class AddNameToGeoNodes < ActiveRecord::Migration[5.0]
DOWNTIME = false
def up
- add_column :geo_nodes, :name, :string
+ add_column :geo_nodes, :name, :string # rubocop:disable Migration/AddLimitToStringColumns
# url is also unique, and its type and size is identical to the name column,
# so this is safe.
diff --git a/db/migrate/20190422082247_create_project_metrics_settings.rb b/db/migrate/20190422082247_create_project_metrics_settings.rb
index 3e21dd0a934..a0a2ed64820 100644
--- a/db/migrate/20190422082247_create_project_metrics_settings.rb
+++ b/db/migrate/20190422082247_create_project_metrics_settings.rb
@@ -7,7 +7,7 @@ class CreateProjectMetricsSettings < ActiveRecord::Migration[5.0]
def change
create_table :project_metrics_settings, id: :int, primary_key: :project_id, default: nil do |t|
- t.string :external_dashboard_url, null: false
+ t.string :external_dashboard_url, null: false # rubocop:disable Migration/AddLimitToStringColumns
t.foreign_key :projects, column: :project_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20190429082448_create_pages_domain_acme_orders.rb b/db/migrate/20190429082448_create_pages_domain_acme_orders.rb
index af811e83518..ca1796d054c 100644
--- a/db/migrate/20190429082448_create_pages_domain_acme_orders.rb
+++ b/db/migrate/20190429082448_create_pages_domain_acme_orders.rb
@@ -10,6 +10,7 @@ class CreatePagesDomainAcmeOrders < ActiveRecord::Migration[5.1]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :pages_domain_acme_orders do |t|
t.references :pages_domain, null: false, index: true, foreign_key: { on_delete: :cascade }, type: :integer
@@ -24,5 +25,6 @@ class CreatePagesDomainAcmeOrders < ActiveRecord::Migration[5.1]
t.text :encrypted_private_key, null: false
t.text :encrypted_private_key_iv, null: false
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190430131225_create_issue_tracker_data.rb b/db/migrate/20190430131225_create_issue_tracker_data.rb
index 7859bea9c22..d2134ad82c7 100644
--- a/db/migrate/20190430131225_create_issue_tracker_data.rb
+++ b/db/migrate/20190430131225_create_issue_tracker_data.rb
@@ -9,6 +9,7 @@ class CreateIssueTrackerData < ActiveRecord::Migration[5.1]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :issue_tracker_data do |t|
t.references :service, foreign_key: { on_delete: :cascade }, type: :integer, index: true, null: false
t.timestamps_with_timezone
@@ -19,5 +20,6 @@ class CreateIssueTrackerData < ActiveRecord::Migration[5.1]
t.string :encrypted_new_issue_url
t.string :encrypted_new_issue_url_iv
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190430142025_create_jira_tracker_data.rb b/db/migrate/20190430142025_create_jira_tracker_data.rb
index d328ad63854..5e53e5a701a 100644
--- a/db/migrate/20190430142025_create_jira_tracker_data.rb
+++ b/db/migrate/20190430142025_create_jira_tracker_data.rb
@@ -9,6 +9,7 @@ class CreateJiraTrackerData < ActiveRecord::Migration[5.1]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :jira_tracker_data do |t|
t.references :service, foreign_key: { on_delete: :cascade }, type: :integer, index: true, null: false
t.timestamps_with_timezone
@@ -22,5 +23,6 @@ class CreateJiraTrackerData < ActiveRecord::Migration[5.1]
t.string :encrypted_password_iv
t.string :jira_issue_transition_id
end
+ # rubocop:enable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190514105711_create_ip_restriction.rb b/db/migrate/20190514105711_create_ip_restriction.rb
index dfafbe32ad1..69f8c1b8c4e 100644
--- a/db/migrate/20190514105711_create_ip_restriction.rb
+++ b/db/migrate/20190514105711_create_ip_restriction.rb
@@ -12,7 +12,7 @@ class CreateIpRestriction < ActiveRecord::Migration[5.1]
type: :integer,
null: false,
index: true
- t.string :range, null: false
+ t.string :range, null: false # rubocop:disable Migration/AddLimitToStringColumns
end
add_foreign_key(:ip_restrictions, :namespaces, column: :group_id, on_delete: :cascade) # rubocop: disable Migration/AddConcurrentForeignKey
diff --git a/db/migrate/20190527011309_add_required_template_name_to_application_settings.rb b/db/migrate/20190527011309_add_required_template_name_to_application_settings.rb
index 6cbac0ed507..5c47e6f33c2 100644
--- a/db/migrate/20190527011309_add_required_template_name_to_application_settings.rb
+++ b/db/migrate/20190527011309_add_required_template_name_to_application_settings.rb
@@ -10,6 +10,6 @@ class AddRequiredTemplateNameToApplicationSettings < ActiveRecord::Migration[5.1
DOWNTIME = false
def change
- add_column :application_settings, :required_instance_ci_template, :string, null: true
+ add_column :application_settings, :required_instance_ci_template, :string, null: true # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190606054742_add_token_encrypted_to_operations_feature_flags_clients.rb b/db/migrate/20190606054742_add_token_encrypted_to_operations_feature_flags_clients.rb
index 024b5bd2ba5..2db4dc85750 100644
--- a/db/migrate/20190606054742_add_token_encrypted_to_operations_feature_flags_clients.rb
+++ b/db/migrate/20190606054742_add_token_encrypted_to_operations_feature_flags_clients.rb
@@ -6,6 +6,6 @@ class AddTokenEncryptedToOperationsFeatureFlagsClients < ActiveRecord::Migration
DOWNTIME = false
def change
- add_column :operations_feature_flags_clients, :token_encrypted, :string
+ add_column :operations_feature_flags_clients, :token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190613044655_add_username_to_deploy_tokens.rb b/db/migrate/20190613044655_add_username_to_deploy_tokens.rb
index 793553afe35..a0acb02013b 100644
--- a/db/migrate/20190613044655_add_username_to_deploy_tokens.rb
+++ b/db/migrate/20190613044655_add_username_to_deploy_tokens.rb
@@ -4,6 +4,6 @@ class AddUsernameToDeployTokens < ActiveRecord::Migration[5.1]
DOWNTIME = false
def change
- add_column :deploy_tokens, :username, :string
+ add_column :deploy_tokens, :username, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190613073003_create_project_aliases.rb b/db/migrate/20190613073003_create_project_aliases.rb
index 5a2c2ba0cf2..896d3ca5813 100644
--- a/db/migrate/20190613073003_create_project_aliases.rb
+++ b/db/migrate/20190613073003_create_project_aliases.rb
@@ -8,7 +8,7 @@ class CreateProjectAliases < ActiveRecord::Migration[5.1]
def change
create_table :project_aliases do |t|
t.references :project, null: false, index: true, foreign_key: { on_delete: :cascade }, type: :integer
- t.string :name, null: false, index: { unique: true }
+ t.string :name, null: false, index: { unique: true } # rubocop:disable Migration/AddLimitToStringColumns
t.timestamps_with_timezone null: false
end
diff --git a/db/migrate/20190621151636_add_merge_request_rebase_jid.rb b/db/migrate/20190621151636_add_merge_request_rebase_jid.rb
index 1fed5690ead..6c1081732e8 100644
--- a/db/migrate/20190621151636_add_merge_request_rebase_jid.rb
+++ b/db/migrate/20190621151636_add_merge_request_rebase_jid.rb
@@ -4,6 +4,6 @@ class AddMergeRequestRebaseJid < ActiveRecord::Migration[5.1]
DOWNTIME = false
def change
- add_column :merge_requests, :rebase_jid, :string
+ add_column :merge_requests, :rebase_jid, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/migrate/20190624123615_add_grafana_url_to_settings.rb b/db/migrate/20190624123615_add_grafana_url_to_settings.rb
index 61efe64a7a1..835ec4e9094 100644
--- a/db/migrate/20190624123615_add_grafana_url_to_settings.rb
+++ b/db/migrate/20190624123615_add_grafana_url_to_settings.rb
@@ -8,8 +8,10 @@ class AddGrafanaUrlToSettings < ActiveRecord::Migration[5.1]
DOWNTIME = false
def up
+ # rubocop:disable Migration/AddLimitToStringColumns
add_column_with_default(:application_settings, :grafana_url, :string,
default: '/-/grafana', allow_null: false)
+ # rubocop:enable Migration/AddLimitToStringColumns
end
def down
diff --git a/db/migrate/20190711124721_create_job_variables.rb b/db/migrate/20190711124721_create_job_variables.rb
index a860522f39e..4ff4b031d8f 100644
--- a/db/migrate/20190711124721_create_job_variables.rb
+++ b/db/migrate/20190711124721_create_job_variables.rb
@@ -10,6 +10,7 @@ class CreateJobVariables < ActiveRecord::Migration[5.1]
DOWNTIME = false
def change
+ # rubocop:disable Migration/AddLimitToStringColumns
create_table :ci_job_variables do |t|
t.string :key, null: false
t.text :encrypted_value
@@ -17,6 +18,7 @@ class CreateJobVariables < ActiveRecord::Migration[5.1]
t.references :job, null: false, index: true, foreign_key: { to_table: :ci_builds, on_delete: :cascade }
t.integer :variable_type, null: false, limit: 2, default: 1
end
+ # rubocop:enable Migration/AddLimitToStringColumns
add_index :ci_job_variables, [:key, :job_id], unique: true
end
diff --git a/db/migrate/20190711200053_change_deploy_tokens_token_not_null.rb b/db/migrate/20190711200053_change_deploy_tokens_token_not_null.rb
new file mode 100644
index 00000000000..14ccf544d0b
--- /dev/null
+++ b/db/migrate/20190711200053_change_deploy_tokens_token_not_null.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class ChangeDeployTokensTokenNotNull < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ change_column_null :deploy_tokens, :token, true
+ end
+end
diff --git a/db/migrate/20190711200508_add_token_encrypted_to_deploy_tokens.rb b/db/migrate/20190711200508_add_token_encrypted_to_deploy_tokens.rb
new file mode 100644
index 00000000000..ea0956fdf7f
--- /dev/null
+++ b/db/migrate/20190711200508_add_token_encrypted_to_deploy_tokens.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddTokenEncryptedToDeployTokens < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column :deploy_tokens, :token_encrypted, :string, limit: 255
+ end
+end
diff --git a/db/migrate/20190719174505_add_index_to_deploy_tokens_token_encrypted.rb b/db/migrate/20190719174505_add_index_to_deploy_tokens_token_encrypted.rb
new file mode 100644
index 00000000000..d58d1d8348c
--- /dev/null
+++ b/db/migrate/20190719174505_add_index_to_deploy_tokens_token_encrypted.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexToDeployTokensTokenEncrypted < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :deploy_tokens, :token_encrypted, unique: true, name: "index_deploy_tokens_on_token_encrypted"
+ end
+
+ def down
+ remove_concurrent_index_by_name :deploy_tokens, "index_deploy_tokens_on_token_encrypted"
+ end
+end
diff --git a/db/migrate/20190726101050_rename_allow_local_requests_from_hooks_and_services_application_setting.rb b/db/migrate/20190726101050_rename_allow_local_requests_from_hooks_and_services_application_setting.rb
index ac65e8d745c..cce8942128c 100644
--- a/db/migrate/20190726101050_rename_allow_local_requests_from_hooks_and_services_application_setting.rb
+++ b/db/migrate/20190726101050_rename_allow_local_requests_from_hooks_and_services_application_setting.rb
@@ -12,6 +12,6 @@ class RenameAllowLocalRequestsFromHooksAndServicesApplicationSetting < ActiveRec
end
def down
- cleanup_concurrent_column_rename :application_settings, :allow_local_requests_from_web_hooks_and_services, :allow_local_requests_from_hooks_and_services
+ undo_rename_column_concurrently :application_settings, :allow_local_requests_from_hooks_and_services, :allow_local_requests_from_web_hooks_and_services
end
end
diff --git a/db/migrate/20190805140353_remove_rendundant_index_from_releases.rb b/db/migrate/20190805140353_remove_rendundant_index_from_releases.rb
new file mode 100644
index 00000000000..fc4bc1a423b
--- /dev/null
+++ b/db/migrate/20190805140353_remove_rendundant_index_from_releases.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveRendundantIndexFromReleases < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index :releases, :project_id
+ end
+
+ def down
+ add_concurrent_index :releases, :project_id
+ end
+end
diff --git a/db/migrate/20190820163320_add_first_last_name_to_user.rb b/db/migrate/20190820163320_add_first_last_name_to_user.rb
new file mode 100644
index 00000000000..0ea465fc2e2
--- /dev/null
+++ b/db/migrate/20190820163320_add_first_last_name_to_user.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddFirstLastNameToUser < ActiveRecord::Migration[5.2]
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :first_name, :string, null: true, limit: 255)
+ add_column(:users, :last_name, :string, null: true, limit: 255)
+ end
+end
diff --git a/db/post_migrate/20181013005024_remove_koding_from_application_settings.rb b/db/post_migrate/20181013005024_remove_koding_from_application_settings.rb
index 550ad94f4ab..b6e5473e896 100644
--- a/db/post_migrate/20181013005024_remove_koding_from_application_settings.rb
+++ b/db/post_migrate/20181013005024_remove_koding_from_application_settings.rb
@@ -12,6 +12,6 @@ class RemoveKodingFromApplicationSettings < ActiveRecord::Migration[4.2]
def down
add_column :application_settings, :koding_enabled, :boolean # rubocop:disable Migration/SaferBooleanColumn
- add_column :application_settings, :koding_url, :string
+ add_column :application_settings, :koding_url, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/post_migrate/20190404231137_remove_alternate_url_from_geo_nodes.rb b/db/post_migrate/20190404231137_remove_alternate_url_from_geo_nodes.rb
index 785ceb2fb28..8e7ef0ec54f 100644
--- a/db/post_migrate/20190404231137_remove_alternate_url_from_geo_nodes.rb
+++ b/db/post_migrate/20190404231137_remove_alternate_url_from_geo_nodes.rb
@@ -16,6 +16,6 @@ class RemoveAlternateUrlFromGeoNodes < ActiveRecord::Migration[5.0]
end
def down
- add_column :geo_nodes, :alternate_url, :string
+ add_column :geo_nodes, :alternate_url, :string # rubocop:disable Migration/AddLimitToStringColumns
end
end
diff --git a/db/post_migrate/20190625184066_remove_sentry_from_application_settings.rb b/db/post_migrate/20190625184066_remove_sentry_from_application_settings.rb
index 427df343193..9d71bfafffb 100644
--- a/db/post_migrate/20190625184066_remove_sentry_from_application_settings.rb
+++ b/db/post_migrate/20190625184066_remove_sentry_from_application_settings.rb
@@ -32,7 +32,7 @@ class RemoveSentryFromApplicationSettings < ActiveRecord::Migration[5.0]
end
SENTRY_DSN_COLUMNS.each do |column|
- add_column(:application_settings, column, :string) unless column_exists?(:application_settings, column)
+ add_column(:application_settings, column, :string) unless column_exists?(:application_settings, column) # rubocop:disable Migration/AddLimitToStringColumns
end
end
end
diff --git a/db/post_migrate/20190711201818_encrypt_deploy_tokens_tokens.rb b/db/post_migrate/20190711201818_encrypt_deploy_tokens_tokens.rb
new file mode 100644
index 00000000000..2eb8d1ee11c
--- /dev/null
+++ b/db/post_migrate/20190711201818_encrypt_deploy_tokens_tokens.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class EncryptDeployTokensTokens < ActiveRecord::Migration[5.1]
+ DOWNTIME = false
+
+ class DeploymentTokens < ActiveRecord::Base
+ self.table_name = 'deploy_tokens'
+ end
+
+ def up
+ say_with_time("Encrypting tokens from deploy_tokens") do
+ DeploymentTokens.where('token_encrypted is NULL AND token IS NOT NULL').find_each(batch_size: 10000) do |deploy_token|
+ token_encrypted = Gitlab::CryptoHelper.aes256_gcm_encrypt(deploy_token.token)
+ deploy_token.update!(token_encrypted: token_encrypted)
+ end
+ end
+ end
+
+ def down
+ say_with_time("Decrypting tokens from deploy_tokens") do
+ DeploymentTokens.where('token_encrypted IS NOT NULL AND token IS NULL').find_each(batch_size: 10000) do |deploy_token|
+ token = Gitlab::CryptoHelper.aes256_gcm_decrypt(deploy_token.token_encrypted)
+ deploy_token.update!(token: token)
+ end
+ end
+ end
+end
diff --git a/db/post_migrate/20190801072937_add_gitlab_instance_administration_project.rb b/db/post_migrate/20190801072937_add_gitlab_instance_administration_project.rb
new file mode 100644
index 00000000000..8b2cf7b3d76
--- /dev/null
+++ b/db/post_migrate/20190801072937_add_gitlab_instance_administration_project.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddGitlabInstanceAdministrationProject < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def up
+ Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService.new.execute!
+ end
+
+ def down
+ ApplicationSetting.current_without_cache
+ &.instance_administration_project
+ &.owner
+ &.destroy!
+ end
+end
diff --git a/db/post_migrate/20190801114109_cleanup_allow_local_requests_from_hooks_and_services_application_setting_rename.rb b/db/post_migrate/20190801114109_cleanup_allow_local_requests_from_hooks_and_services_application_setting_rename.rb
index 127e44254ac..cb86f843f9c 100644
--- a/db/post_migrate/20190801114109_cleanup_allow_local_requests_from_hooks_and_services_application_setting_rename.rb
+++ b/db/post_migrate/20190801114109_cleanup_allow_local_requests_from_hooks_and_services_application_setting_rename.rb
@@ -12,6 +12,6 @@ class CleanupAllowLocalRequestsFromHooksAndServicesApplicationSettingRename < Ac
end
def down
- rename_column_concurrently :application_settings, :allow_local_requests_from_web_hooks_and_services, :allow_local_requests_from_hooks_and_services
+ undo_cleanup_concurrent_column_rename :application_settings, :allow_local_requests_from_hooks_and_services, :allow_local_requests_from_web_hooks_and_services
end
end
diff --git a/db/post_migrate/20190809072552_set_self_monitoring_project_alerting_token.rb b/db/post_migrate/20190809072552_set_self_monitoring_project_alerting_token.rb
new file mode 100644
index 00000000000..0c4faebc548
--- /dev/null
+++ b/db/post_migrate/20190809072552_set_self_monitoring_project_alerting_token.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+class SetSelfMonitoringProjectAlertingToken < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ module Migratable
+ module Alerting
+ class ProjectAlertingSetting < ApplicationRecord
+ self.table_name = 'project_alerting_settings'
+
+ belongs_to :project
+
+ validates :token, presence: true
+
+ attr_encrypted :token,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ algorithm: 'aes-256-gcm'
+
+ before_validation :ensure_token
+
+ private
+
+ def ensure_token
+ self.token ||= generate_token
+ end
+
+ def generate_token
+ SecureRandom.hex
+ end
+ end
+ end
+
+ class Project < ApplicationRecord
+ has_one :alerting_setting, inverse_of: :project, class_name: 'Alerting::ProjectAlertingSetting'
+ end
+
+ class ApplicationSetting < ApplicationRecord
+ self.table_name = 'application_settings'
+
+ belongs_to :instance_administration_project, class_name: 'Project'
+
+ def self.current_without_cache
+ last
+ end
+ end
+ end
+
+ def setup_alertmanager_token(project)
+ return unless License.feature_available?(:prometheus_alerts)
+
+ project.create_alerting_setting!
+ end
+
+ def up
+ Gitlab.ee do
+ project = Migratable::ApplicationSetting.current_without_cache&.instance_administration_project
+
+ if project
+ setup_alertmanager_token(project)
+ end
+ end
+ end
+
+ def down
+ Gitlab.ee do
+ Migratable::ApplicationSetting.current_without_cache
+ &.instance_administration_project
+ &.alerting_setting
+ &.destroy!
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 3f7917654cf..f30dad3d030 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_08_15_093949) do
+ActiveRecord::Schema.define(version: 2019_08_20_163320) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -1121,10 +1121,12 @@ ActiveRecord::Schema.define(version: 2019_08_15_093949) do
t.datetime_with_timezone "expires_at", null: false
t.datetime_with_timezone "created_at", null: false
t.string "name", null: false
- t.string "token", null: false
+ t.string "token"
t.string "username"
+ t.string "token_encrypted", limit: 255
t.index ["token", "expires_at", "id"], name: "index_deploy_tokens_on_token_and_expires_at_and_id", where: "(revoked IS FALSE)"
t.index ["token"], name: "index_deploy_tokens_on_token", unique: true
+ t.index ["token_encrypted"], name: "index_deploy_tokens_on_token_encrypted", unique: true
end
create_table "deployments", id: :serial, force: :cascade do |t|
@@ -3015,7 +3017,6 @@ ActiveRecord::Schema.define(version: 2019_08_15_093949) do
t.datetime_with_timezone "released_at", null: false
t.index ["author_id"], name: "index_releases_on_author_id"
t.index ["project_id", "tag"], name: "index_releases_on_project_id_and_tag"
- t.index ["project_id"], name: "index_releases_on_project_id"
end
create_table "remote_mirrors", id: :serial, force: :cascade do |t|
@@ -3512,6 +3513,8 @@ ActiveRecord::Schema.define(version: 2019_08_15_093949) do
t.text "note"
t.integer "roadmap_layout", limit: 2
t.integer "bot_type", limit: 2
+ t.string "first_name", limit: 255
+ t.string "last_name", limit: 255
t.index ["accepted_term_id"], name: "index_users_on_accepted_term_id"
t.index ["admin"], name: "index_users_on_admin"
t.index ["bot_type"], name: "index_users_on_bot_type"
diff --git a/doc/administration/database_load_balancing.md b/doc/administration/database_load_balancing.md
index dc4cc401fca..64eca0b00f6 100644
--- a/doc/administration/database_load_balancing.md
+++ b/doc/administration/database_load_balancing.md
@@ -122,6 +122,7 @@ production:
discover:
nameserver: localhost
record: secondary.postgresql.service.consul
+ record_type: A
port: 8600
interval: 60
disconnect_timeout: 120
@@ -137,12 +138,16 @@ The following options can be set:
| Option | Description | Default |
|----------------------|---------------------------------------------------------------------------------------------------|-----------|
| `nameserver` | The nameserver to use for looking up the DNS record. | localhost |
-| `record` | The A record to look up. This option is required for service discovery to work. | |
+| `record` | The record to look up. This option is required for service discovery to work. | |
+| `record_type` | Optional record type to look up, this can be either A or SRV (since GitLab 12.3) | A |
| `port` | The port of the nameserver. | 8600 |
| `interval` | The minimum time in seconds between checking the DNS record. | 60 |
| `disconnect_timeout` | The time in seconds after which an old connection is closed, after the list of hosts was updated. | 120 |
| `use_tcp` | Lookup DNS resources using TCP instead of UDP | false |
+If `record_type` is set to `SRV`, GitLab will continue to use a round-robin algorithm
+and will ignore the `weight` and `priority` in the record.
+
The `interval` value specifies the _minimum_ time between checks. If the A
record has a TTL greater than this value, then service discovery will honor said
TTL. For example, if the TTL of the A record is 90 seconds, then service
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index e0a06e71316..daec5f14e36 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -139,7 +139,7 @@ Git operations in GitLab will result in an API error.
NOTE: **Note:**
In most or all cases, the storage paths below end in `/repositories` which is
-not that case with `path` in `git_data_dirs` of Omnibus GitLab installations.
+not the case with `path` in `git_data_dirs` of Omnibus GitLab installations.
Check the directory layout on your Gitaly server to be sure.
**For Omnibus GitLab**
@@ -283,10 +283,6 @@ can read and write to `/mnt/gitlab/storage2`.
gitlab_rails['gitaly_token'] = 'abc123secret'
```
- NOTE: **Note:**
- In some cases, you'll have to set `path` for each `git_data_dirs` in the
- format `'path' => '/mnt/gitlab/<storage name>'`.
-
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Tail the logs to see the requests:
@@ -304,18 +300,22 @@ can read and write to `/mnt/gitlab/storage2`.
storages:
default:
gitaly_address: tcp://gitaly1.internal:8075
+ path: /some/dummy/path
storage1:
gitaly_address: tcp://gitaly1.internal:8075
+ path: /some/dummy/path
storage2:
gitaly_address: tcp://gitaly2.internal:8075
+ path: /some/dummy/path
gitaly:
token: 'abc123secret'
```
NOTE: **Note:**
- In some cases, you'll have to set `path` for each of the `storages` in the
- format `path: /mnt/gitlab/<storage name>/repositories`.
+ `/some/dummy/path` should be set to a local folder that exists, however no
+ data will be stored in this folder. This will no longer be necessary after
+ [this issue](https://gitlab.com/gitlab-org/gitaly/issues/1282) is resolved.
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source).
1. Tail the logs to see the requests:
@@ -416,18 +416,22 @@ To configure Gitaly with TLS:
storages:
default:
gitaly_address: tls://gitaly1.internal:9999
+ path: /some/dummy/path
storage1:
gitaly_address: tls://gitaly1.internal:9999
+ path: /some/dummy/path
storage2:
gitaly_address: tls://gitaly2.internal:9999
+ path: /some/dummy/path
gitaly:
token: 'abc123secret'
```
NOTE: **Note:**
- In some cases, you'll have to set `path` for each of the `storages` in the
- format `path: /mnt/gitlab/<storage name>/repositories`.
+ `/some/dummy/path` should be set to a local folder that exists, however no
+ data will be stored in this folder. This will no longer be necessary after
+ [this issue](https://gitlab.com/gitlab-org/gitaly/issues/1282) is resolved.
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source).
1. On the Gitaly server nodes, edit `/home/git/gitaly/config.toml`:
@@ -514,6 +518,47 @@ One current feature of GitLab that still requires a shared directory (NFS) is
There is [work in progress](https://gitlab.com/gitlab-org/gitlab-pages/issues/196)
to eliminate the need for NFS to support GitLab Pages.
+## Limiting RPC concurrency
+
+It can happen that CI clone traffic puts a large strain on your Gitaly
+service. The bulk of the work gets done in the SSHUploadPack (for Git
+SSH) and PostUploadPack (for Git HTTP) RPC's. To prevent such workloads
+from overcrowding your Gitaly server you can set concurrency limits in
+Gitaly's configuration file.
+
+```ruby
+# in /etc/gitlab/gitlab.rb
+
+gitaly['concurrency'] = [
+ {
+ 'rpc' => "/gitaly.SmartHTTPService/PostUploadPack",
+ 'max_per_repo' => 20
+ },
+ {
+ 'rpc' => "/gitaly.SSHService/SSHUploadPack",
+ 'max_per_repo' => 20
+ }
+]
+```
+This will limit the number of in-flight RPC calls for the given RPC's.
+The limit is applied per repository. In the example above, each on the
+Gitaly server can have at most 20 simultaneous PostUploadPack calls in
+flight, and the same for SSHUploadPack. If another request comes in for
+a repository that hase used up its 20 slots, that request will get
+queued.
+
+You can observe the behavior of this queue via the Gitaly logs and via
+Prometheus. In the Gitaly logs, you can look for the string (or
+structured log field) `acquire_ms`. Messages that have this field are
+reporting about the concurrency limiter. In Prometheus, look for the
+`gitaly_rate_limiting_in_progress`, `gitaly_rate_limiting_queued` and
+`gitaly_rate_limiting_seconds` metrics.
+
+The name of the Prometheus metric is not quite right because this is a
+concurrency limiter, not a rate limiter. If a client makes 1000 requests
+in a row in a very short timespan, the concurrency will not exceed 1,
+and this mechanism (the concurrency limiter) will do nothing.
+
## Troubleshooting Gitaly
### Commits, pushes, and clones return a 401
diff --git a/doc/administration/issue_closing_pattern.md b/doc/administration/issue_closing_pattern.md
index 66ab3ef8d81..f9be06c6daf 100644
--- a/doc/administration/issue_closing_pattern.md
+++ b/doc/administration/issue_closing_pattern.md
@@ -1,8 +1,8 @@
# Issue closing pattern **(CORE ONLY)**
>**Note:**
-This is the administration documentation.
-There is a separate [user documentation] on issue closing pattern.
+This is the administration documentation. There is a separate [user documentation](../user/project/issues/managing_issues.md#closing-issues-automatically)
+on issue closing pattern.
When a commit or merge request resolves one or more issues, it is possible to
automatically have these issues closed when the commit or merge request lands
@@ -13,8 +13,8 @@ in the project's default branch.
In order to change the pattern you need to have access to the server that GitLab
is installed on.
-The default pattern can be located in [`gitlab.yml.example`] under the
-"Automatic issue closing" section.
+The default pattern can be located in [`gitlab.yml.example`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example)
+under the "Automatic issue closing" section.
> **Tip:**
You are advised to use <http://rubular.com> to test the issue closing pattern.
@@ -31,7 +31,7 @@ Because Rubular doesn't understand `%{issue_ref}`, you can replace this by
gitlab_rails['gitlab_issue_closing_pattern'] = "\b((?:[Cc]los(?:e[sd]|ing)|\b[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)"
```
-1. [Reconfigure] GitLab for the changes to take effect.
+1. [Reconfigure](restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab for the changes to take effect.
**For installations from source**
@@ -42,9 +42,4 @@ Because Rubular doesn't understand `%{issue_ref}`, you can replace this by
issue_closing_pattern: "\b((?:[Cc]los(?:e[sd]|ing)|\b[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)"
```
-1. [Restart] GitLab for the changes to take effect.
-
-[gitlab.yml.example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example
-[reconfigure]: restart_gitlab.md#omnibus-gitlab-reconfigure
-[restart]: restart_gitlab.md#installations-from-source
-[user documentation]: ../user/project/issues/managing_issues.md#closing-issues-automatically
+1. [Restart](restart_gitlab.md#installations-from-source) GitLab for the changes to take effect.
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index 0605fb76e2f..4809bee0df6 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -1,7 +1,7 @@
# GitLab Prometheus metrics
>**Note:**
-Available since [Omnibus GitLab 9.3][29118]. For
+Available since [Omnibus GitLab 9.3](https://gitlab.com/gitlab-org/gitlab-ce/issues/29118). For
installations from source you'll have to configure it yourself.
To enable the GitLab Prometheus metrics:
@@ -9,13 +9,13 @@ To enable the GitLab Prometheus metrics:
1. Log into GitLab as an administrator, and go to the Admin area.
1. Click on the gear, then click on Settings.
1. Find the `Metrics - Prometheus` section, and click `Enable Prometheus Metrics`
-1. [Restart GitLab][restart] for the changes to take effect
+1. [Restart GitLab](../../restart_gitlab.md#omnibus-gitlab-restart) for the changes to take effect
## Collecting the metrics
GitLab monitors its own internal service metrics, and makes them available at the
-`/-/metrics` endpoint. Unlike other [Prometheus] exporters, in order to access
-it, the client IP needs to be [included in a whitelist][whitelist].
+`/-/metrics` endpoint. Unlike other [Prometheus](https://prometheus.io) exporters, in order to access
+it, the client IP needs to be [included in a whitelist](../ip_whitelist.md).
For Omnibus and Chart installations, these metrics are automatically enabled and collected as of [GitLab 9.4](https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/1702). For source installations or earlier versions, these metrics will need to be enabled manually and collected by a Prometheus server.
@@ -23,159 +23,159 @@ For Omnibus and Chart installations, these metrics are automatically enabled and
The following metrics are available:
-| Metric | Type | Since | Description | Labels |
-|:-------------------------------------------------------------|:----------|-----------------------:|:----------------------------------------------------------------------------------------------------|:----------------------------------------------------|
-| gitlab_banzai_cached_render_real_duration_seconds | Histogram | 9.4 | Duration of rendering markdown into HTML when cached output exists | controller, action |
-| gitlab_banzai_cacheless_render_real_duration_seconds | Histogram | 9.4 | Duration of rendering markdown into HTML when cached outupt does not exist | controller, action |
-| gitlab_cache_misses_total | Counter | 10.2 | Cache read miss | controller, action |
-| gitlab_cache_operation_duration_seconds | Histogram | 10.2 | Cache access time | |
-| gitlab_cache_operations_total | Counter | 12.2 | Cache operations by controller/action | controller, action, operation |
-| gitlab_database_transaction_seconds | Histogram | 12.1 | Time spent in database transactions, in seconds | |
-| gitlab_method_call_duration_seconds | Histogram | 10.2 | Method calls real duration | controller, action, module, method |
-| gitlab_rails_queue_duration_seconds | Histogram | 9.4 | Measures latency between gitlab-workhorse forwarding a request to Rails | |
-| gitlab_sql_duration_seconds | Histogram | 10.2 | SQL execution time, excluding SCHEMA operations and BEGIN / COMMIT | |
-| gitlab_transaction_allocated_memory_bytes | Histogram | 10.2 | Allocated memory for all transactions (gitlab_transaction_* metrics) | |
-| gitlab_transaction_cache_<key>_count_total | Counter | 10.2 | Counter for total Rails cache calls (per key) | |
-| gitlab_transaction_cache_<key>_duration_total | Counter | 10.2 | Counter for total time (seconds) spent in Rails cache calls (per key) | |
-| gitlab_transaction_cache_count_total | Counter | 10.2 | Counter for total Rails cache calls (aggregate) | |
-| gitlab_transaction_cache_duration_total | Counter | 10.2 | Counter for total time (seconds) spent in Rails cache calls (aggregate) | |
-| gitlab_transaction_cache_read_hit_count_total | Counter | 10.2 | Counter for cache hits for Rails cache calls | controller, action |
-| gitlab_transaction_cache_read_miss_count_total | Counter | 10.2 | Counter for cache misses for Rails cache calls | controller, action |
-| gitlab_transaction_duration_seconds | Histogram | 10.2 | Duration for all transactions (gitlab_transaction_* metrics) | controller, action |
-| gitlab_transaction_event_build_found_total | Counter | 9.4 | Counter for build found for api /jobs/request | |
-| gitlab_transaction_event_build_invalid_total | Counter | 9.4 | Counter for build invalid due to concurrency conflict for api /jobs/request | |
-| gitlab_transaction_event_build_not_found_cached_total | Counter | 9.4 | Counter for cached response of build not found for api /jobs/request | |
-| gitlab_transaction_event_build_not_found_total | Counter | 9.4 | Counter for build not found for api /jobs/request | |
-| gitlab_transaction_event_change_default_branch_total | Counter | 9.4 | Counter when default branch is changed for any repository | |
-| gitlab_transaction_event_create_repository_total | Counter | 9.4 | Counter when any repository is created | |
-| gitlab_transaction_event_etag_caching_cache_hit_total | Counter | 9.4 | Counter for etag cache hit. | endpoint |
-| gitlab_transaction_event_etag_caching_header_missing_total | Counter | 9.4 | Counter for etag cache miss - header missing | endpoint |
-| gitlab_transaction_event_etag_caching_key_not_found_total | Counter | 9.4 | Counter for etag cache miss - key not found | endpoint |
-| gitlab_transaction_event_etag_caching_middleware_used_total | Counter | 9.4 | Counter for etag middleware accessed | endpoint |
-| gitlab_transaction_event_etag_caching_resource_changed_total | Counter | 9.4 | Counter for etag cache miss - resource changed | endpoint |
-| gitlab_transaction_event_fork_repository_total | Counter | 9.4 | Counter for repository forks (RepositoryForkWorker). Only incremented when source repository exists | |
-| gitlab_transaction_event_import_repository_total | Counter | 9.4 | Counter for repository imports (RepositoryImportWorker) | |
-| gitlab_transaction_event_push_branch_total | Counter | 9.4 | Counter for all branch pushes | |
-| gitlab_transaction_event_push_commit_total | Counter | 9.4 | Counter for commits | branch |
-| gitlab_transaction_event_push_tag_total | Counter | 9.4 | Counter for tag pushes | |
-| gitlab_transaction_event_rails_exception_total | Counter | 9.4 | Counter for number of rails exceptions | |
-| gitlab_transaction_event_receive_email_total | Counter | 9.4 | Counter for recieved emails | handler |
-| gitlab_transaction_event_remote_mirrors_failed_total | Counter | 10.8 | Counter for failed remote mirrors | |
-| gitlab_transaction_event_remote_mirrors_finished_total | Counter | 10.8 | Counter for finished remote mirrors | |
-| gitlab_transaction_event_remote_mirrors_running_total | Counter | 10.8 | Counter for running remote mirrors | |
-| gitlab_transaction_event_remove_branch_total | Counter | 9.4 | Counter when a branch is removed for any repository | |
-| gitlab_transaction_event_remove_repository_total | Counter | 9.4 | Counter when a repository is removed | |
-| gitlab_transaction_event_remove_tag_total | Counter | 9.4 | Counter when a tag is remove for any repository | |
-| gitlab_transaction_event_sidekiq_exception_total | Counter | 9.4 | Counter of sidekiq exceptions | |
-| gitlab_transaction_event_stuck_import_jobs_total | Counter | 9.4 | Count of stuck import jobs | projects_without_jid_count, projects_with_jid_count |
-| gitlab_transaction_event_update_build_total | Counter | 9.4 | Counter for update build for api /jobs/request/:id | |
-| gitlab_transaction_new_redis_connections_total | Counter | 9.4 | Counter for new redis connections | |
-| gitlab_transaction_queue_duration_total | Counter | 9.4 | Duration jobs were enqueued before processing | |
-| gitlab_transaction_rails_queue_duration_total | Counter | 9.4 | Measures latency between gitlab-workhorse forwarding a request to Rails | controller, action |
-| gitlab_transaction_view_duration_total | Counter | 9.4 | Duration for views | controller, action, view |
-| gitlab_view_rendering_duration_seconds | Histogram | 10.2 | Duration for views (histogram) | controller, action, view |
-| http_requests_total | Counter | 9.4 | Rack request count | method |
-| http_request_duration_seconds | Histogram | 9.4 | HTTP response time from rack middleware | method, status |
-| pipelines_created_total | Counter | 9.4 | Counter of pipelines created | |
-| rack_uncaught_errors_total | Counter | 9.4 | Rack connections handling uncaught errors count | |
-| user_session_logins_total | Counter | 9.4 | Counter of how many users have logged in | |
-| upload_file_does_not_exist | Counter | 10.7 in EE, 11.5 in CE | Number of times an upload record could not find its file | |
-| failed_login_captcha_total | Gauge | 11.0 | Counter of failed CAPTCHA attempts during login | |
-| successful_login_captcha_total | Gauge | 11.0 | Counter of successful CAPTCHA attempts during login | |
+| Metric | Type | Since | Description | Labels |
+|:---------------------------------------------------------------|:----------|-----------------------:|:----------------------------------------------------------------------------------------------------|:----------------------------------------------------|
+| `gitlab_banzai_cached_render_real_duration_seconds` | Histogram | 9.4 | Duration of rendering markdown into HTML when cached output exists | controller, action |
+| `gitlab_banzai_cacheless_render_real_duration_seconds` | Histogram | 9.4 | Duration of rendering markdown into HTML when cached outupt does not exist | controller, action |
+| `gitlab_cache_misses_total` | Counter | 10.2 | Cache read miss | controller, action |
+| `gitlab_cache_operation_duration_seconds` | Histogram | 10.2 | Cache access time | |
+| `gitlab_cache_operations_total` | Counter | 12.2 | Cache operations by controller/action | controller, action, operation |
+| `gitlab_database_transaction_seconds` | Histogram | 12.1 | Time spent in database transactions, in seconds | |
+| `gitlab_method_call_duration_seconds` | Histogram | 10.2 | Method calls real duration | controller, action, module, method |
+| `gitlab_rails_queue_duration_seconds` | Histogram | 9.4 | Measures latency between GitLab Workhorse forwarding a request to Rails | |
+| `gitlab_sql_duration_seconds` | Histogram | 10.2 | SQL execution time, excluding SCHEMA operations and BEGIN / COMMIT | |
+| `gitlab_transaction_allocated_memory_bytes` | Histogram | 10.2 | Allocated memory for all transactions (gitlab_transaction_* metrics) | |
+| `gitlab_transaction_cache_<key>_count_total` | Counter | 10.2 | Counter for total Rails cache calls (per key) | |
+| `gitlab_transaction_cache_<key>_duration_total` | Counter | 10.2 | Counter for total time (seconds) spent in Rails cache calls (per key) | |
+| `gitlab_transaction_cache_count_total` | Counter | 10.2 | Counter for total Rails cache calls (aggregate) | |
+| `gitlab_transaction_cache_duration_total` | Counter | 10.2 | Counter for total time (seconds) spent in Rails cache calls (aggregate) | |
+| `gitlab_transaction_cache_read_hit_count_total` | Counter | 10.2 | Counter for cache hits for Rails cache calls | controller, action |
+| `gitlab_transaction_cache_read_miss_count_total` | Counter | 10.2 | Counter for cache misses for Rails cache calls | controller, action |
+| `gitlab_transaction_duration_seconds` | Histogram | 10.2 | Duration for all transactions (gitlab_transaction_* metrics) | controller, action |
+| `gitlab_transaction_event_build_found_total` | Counter | 9.4 | Counter for build found for api /jobs/request | |
+| `gitlab_transaction_event_build_invalid_total` | Counter | 9.4 | Counter for build invalid due to concurrency conflict for api /jobs/request | |
+| `gitlab_transaction_event_build_not_found_cached_total` | Counter | 9.4 | Counter for cached response of build not found for api /jobs/request | |
+| `gitlab_transaction_event_build_not_found_total` | Counter | 9.4 | Counter for build not found for api /jobs/request | |
+| `gitlab_transaction_event_change_default_branch_total` | Counter | 9.4 | Counter when default branch is changed for any repository | |
+| `gitlab_transaction_event_create_repository_total` | Counter | 9.4 | Counter when any repository is created | |
+| `gitlab_transaction_event_etag_caching_cache_hit_total` | Counter | 9.4 | Counter for etag cache hit. | endpoint |
+| `gitlab_transaction_event_etag_caching_header_missing_total` | Counter | 9.4 | Counter for etag cache miss - header missing | endpoint |
+| `gitlab_transaction_event_etag_caching_key_not_found_total` | Counter | 9.4 | Counter for etag cache miss - key not found | endpoint |
+| `gitlab_transaction_event_etag_caching_middleware_used_total` | Counter | 9.4 | Counter for etag middleware accessed | endpoint |
+| `gitlab_transaction_event_etag_caching_resource_changed_total` | Counter | 9.4 | Counter for etag cache miss - resource changed | endpoint |
+| `gitlab_transaction_event_fork_repository_total` | Counter | 9.4 | Counter for repository forks (RepositoryForkWorker). Only incremented when source repository exists | |
+| `gitlab_transaction_event_import_repository_total` | Counter | 9.4 | Counter for repository imports (RepositoryImportWorker) | |
+| `gitlab_transaction_event_push_branch_total` | Counter | 9.4 | Counter for all branch pushes | |
+| `gitlab_transaction_event_push_commit_total` | Counter | 9.4 | Counter for commits | branch |
+| `gitlab_transaction_event_push_tag_total` | Counter | 9.4 | Counter for tag pushes | |
+| `gitlab_transaction_event_rails_exception_total` | Counter | 9.4 | Counter for number of rails exceptions | |
+| `gitlab_transaction_event_receive_email_total` | Counter | 9.4 | Counter for recieved emails | handler |
+| `gitlab_transaction_event_remote_mirrors_failed_total` | Counter | 10.8 | Counter for failed remote mirrors | |
+| `gitlab_transaction_event_remote_mirrors_finished_total` | Counter | 10.8 | Counter for finished remote mirrors | |
+| `gitlab_transaction_event_remote_mirrors_running_total` | Counter | 10.8 | Counter for running remote mirrors | |
+| `gitlab_transaction_event_remove_branch_total` | Counter | 9.4 | Counter when a branch is removed for any repository | |
+| `gitlab_transaction_event_remove_repository_total` | Counter | 9.4 | Counter when a repository is removed | |
+| `gitlab_transaction_event_remove_tag_total` | Counter | 9.4 | Counter when a tag is remove for any repository | |
+| `gitlab_transaction_event_sidekiq_exception_total` | Counter | 9.4 | Counter of sidekiq exceptions | |
+| `gitlab_transaction_event_stuck_import_jobs_total` | Counter | 9.4 | Count of stuck import jobs | projects_without_jid_count, projects_with_jid_count |
+| `gitlab_transaction_event_update_build_total` | Counter | 9.4 | Counter for update build for api /jobs/request/:id | |
+| `gitlab_transaction_new_redis_connections_total` | Counter | 9.4 | Counter for new redis connections | |
+| `gitlab_transaction_queue_duration_total` | Counter | 9.4 | Duration jobs were enqueued before processing | |
+| `gitlab_transaction_rails_queue_duration_total` | Counter | 9.4 | Measures latency between GitLab Workhorse forwarding a request to Rails | controller, action |
+| `gitlab_transaction_view_duration_total` | Counter | 9.4 | Duration for views | controller, action, view |
+| `gitlab_view_rendering_duration_seconds` | Histogram | 10.2 | Duration for views (histogram) | controller, action, view |
+| `http_requests_total` | Counter | 9.4 | Rack request count | method |
+| `http_request_duration_seconds` | Histogram | 9.4 | HTTP response time from rack middleware | method, status |
+| `pipelines_created_total` | Counter | 9.4 | Counter of pipelines created | |
+| `rack_uncaught_errors_total` | Counter | 9.4 | Rack connections handling uncaught errors count | |
+| `user_session_logins_total` | Counter | 9.4 | Counter of how many users have logged in | |
+| `upload_file_does_not_exist` | Counter | 10.7 in EE, 11.5 in CE | Number of times an upload record could not find its file | |
+| `failed_login_captcha_total` | Gauge | 11.0 | Counter of failed CAPTCHA attempts during login | |
+| `successful_login_captcha_total` | Gauge | 11.0 | Counter of successful CAPTCHA attempts during login | |
## Metrics controlled by a feature flag
The following metrics can be controlled by feature flags:
-| Metric | Feature Flag |
-|:-------------------------------------------------------------|:-----------------------------------------------------------------|
-| gitlab_method_call_duration_seconds | prometheus_metrics_method_instrumentation |
-| gitlab_transaction_allocated_memory_bytes | prometheus_metrics_transaction_allocated_memory |
-| gitlab_transaction_event_build_found_total | prometheus_transaction_event_build_found_total |
-| gitlab_transaction_event_build_invalid_total | prometheus_transaction_event_build_invalid_total |
-| gitlab_transaction_event_build_not_found_cached_total | prometheus_transaction_event_build_not_found_cached_total |
-| gitlab_transaction_event_build_not_found_total | prometheus_transaction_event_build_not_found_total |
-| gitlab_transaction_event_change_default_branch_total | prometheus_transaction_event_change_default_branch_total |
-| gitlab_transaction_event_create_repository_total | prometheus_transaction_event_create_repository_total |
-| gitlab_transaction_event_etag_caching_cache_hit_total | prometheus_transaction_event_etag_caching_cache_hit_total |
-| gitlab_transaction_event_etag_caching_header_missing_total | prometheus_transaction_event_etag_caching_header_missing_total |
-| gitlab_transaction_event_etag_caching_key_not_found_total | prometheus_transaction_event_etag_caching_key_not_found_total |
-| gitlab_transaction_event_etag_caching_middleware_used_total | prometheus_transaction_event_etag_caching_middleware_used_total |
-| gitlab_transaction_event_etag_caching_resource_changed_total | prometheus_transaction_event_etag_caching_resource_changed_total |
-| gitlab_transaction_event_fork_repository_total | prometheus_transaction_event_fork_repository_total |
-| gitlab_transaction_event_import_repository_total | prometheus_transaction_event_import_repository_total |
-| gitlab_transaction_event_push_branch_total | prometheus_transaction_event_push_branch_total |
-| gitlab_transaction_event_push_commit_total | prometheus_transaction_event_push_commit_total |
-| gitlab_transaction_event_push_tag_total | prometheus_transaction_event_push_tag_total |
-| gitlab_transaction_event_rails_exception_total | prometheus_transaction_event_rails_exception_total |
-| gitlab_transaction_event_receive_email_total | prometheus_transaction_event_receive_email_total |
-| gitlab_transaction_event_remote_mirrors_failed_total | prometheus_transaction_event_remote_mirrors_failed_total |
-| gitlab_transaction_event_remote_mirrors_finished_total | prometheus_transaction_event_remote_mirrors_finished_total |
-| gitlab_transaction_event_remote_mirrors_running_total | prometheus_transaction_event_remote_mirrors_running_total |
-| gitlab_transaction_event_remove_branch_total | prometheus_transaction_event_remove_branch_total |
-| gitlab_transaction_event_remove_repository_total | prometheus_transaction_event_remove_repository_total |
-| gitlab_transaction_event_remove_tag_total | prometheus_transaction_event_remove_tag_total |
-| gitlab_transaction_event_sidekiq_exception_total | prometheus_transaction_event_sidekiq_exception_total |
-| gitlab_transaction_event_stuck_import_jobs_total | prometheus_transaction_event_stuck_import_jobs_total |
-| gitlab_transaction_event_update_build_total | prometheus_transaction_event_update_build_total |
-| gitlab_view_rendering_duration_seconds | prometheus_metrics_view_instrumentation |
+| Metric | Feature Flag |
+|:---------------------------------------------------------------|:-------------------------------------------------------------------|
+| `gitlab_method_call_duration_seconds` | `prometheus_metrics_method_instrumentation` |
+| `gitlab_transaction_allocated_memory_bytes` | `prometheus_metrics_transaction_allocated_memory` |
+| `gitlab_transaction_event_build_found_total` | `prometheus_transaction_event_build_found_total` |
+| `gitlab_transaction_event_build_invalid_total` | `prometheus_transaction_event_build_invalid_total` |
+| `gitlab_transaction_event_build_not_found_cached_total` | `prometheus_transaction_event_build_not_found_cached_total` |
+| `gitlab_transaction_event_build_not_found_total` | `prometheus_transaction_event_build_not_found_total` |
+| `gitlab_transaction_event_change_default_branch_total` | `prometheus_transaction_event_change_default_branch_total` |
+| `gitlab_transaction_event_create_repository_total` | `prometheus_transaction_event_create_repository_total` |
+| `gitlab_transaction_event_etag_caching_cache_hit_total` | `prometheus_transaction_event_etag_caching_cache_hit_total` |
+| `gitlab_transaction_event_etag_caching_header_missing_total` | `prometheus_transaction_event_etag_caching_header_missing_total` |
+| `gitlab_transaction_event_etag_caching_key_not_found_total` | `prometheus_transaction_event_etag_caching_key_not_found_total` |
+| `gitlab_transaction_event_etag_caching_middleware_used_total` | `prometheus_transaction_event_etag_caching_middleware_used_total` |
+| `gitlab_transaction_event_etag_caching_resource_changed_total` | `prometheus_transaction_event_etag_caching_resource_changed_total` |
+| `gitlab_transaction_event_fork_repository_total` | `prometheus_transaction_event_fork_repository_total` |
+| `gitlab_transaction_event_import_repository_total` | `prometheus_transaction_event_import_repository_total` |
+| `gitlab_transaction_event_push_branch_total` | `prometheus_transaction_event_push_branch_total` |
+| `gitlab_transaction_event_push_commit_total` | `prometheus_transaction_event_push_commit_total` |
+| `gitlab_transaction_event_push_tag_total` | `prometheus_transaction_event_push_tag_total` |
+| `gitlab_transaction_event_rails_exception_total` | `prometheus_transaction_event_rails_exception_total` |
+| `gitlab_transaction_event_receive_email_total` | `prometheus_transaction_event_receive_email_total` |
+| `gitlab_transaction_event_remote_mirrors_failed_total` | `prometheus_transaction_event_remote_mirrors_failed_total` |
+| `gitlab_transaction_event_remote_mirrors_finished_total` | `prometheus_transaction_event_remote_mirrors_finished_total` |
+| `gitlab_transaction_event_remote_mirrors_running_total` | `prometheus_transaction_event_remote_mirrors_running_total` |
+| `gitlab_transaction_event_remove_branch_total` | `prometheus_transaction_event_remove_branch_total` |
+| `gitlab_transaction_event_remove_repository_total` | `prometheus_transaction_event_remove_repository_total` |
+| `gitlab_transaction_event_remove_tag_total` | `prometheus_transaction_event_remove_tag_total` |
+| `gitlab_transaction_event_sidekiq_exception_total` | `prometheus_transaction_event_sidekiq_exception_total` |
+| `gitlab_transaction_event_stuck_import_jobs_total` | `prometheus_transaction_event_stuck_import_jobs_total` |
+| `gitlab_transaction_event_update_build_total` | `prometheus_transaction_event_update_build_total` |
+| `gitlab_view_rendering_duration_seconds` | `prometheus_metrics_view_instrumentation` |
## Sidekiq Metrics available for Geo **(PREMIUM)**
Sidekiq jobs may also gather metrics, and these metrics can be accessed if the Sidekiq exporter is enabled (e.g. via
the `monitoring.sidekiq_exporter` configuration option in `gitlab.yml`.
-| Metric | Type | Since | Description | Labels |
-|:-------------------------------------------- |:------- |:----- |:----------- |:------ |
-| geo_db_replication_lag_seconds | Gauge | 10.2 | Database replication lag (seconds) | url
-| geo_repositories | Gauge | 10.2 | Total number of repositories available on primary | url
-| geo_repositories_synced | Gauge | 10.2 | Number of repositories synced on secondary | url
-| geo_repositories_failed | Gauge | 10.2 | Number of repositories failed to sync on secondary | url
-| geo_lfs_objects | Gauge | 10.2 | Total number of LFS objects available on primary | url
-| geo_lfs_objects_synced | Gauge | 10.2 | Number of LFS objects synced on secondary | url
-| geo_lfs_objects_failed | Gauge | 10.2 | Number of LFS objects failed to sync on secondary | url
-| geo_attachments | Gauge | 10.2 | Total number of file attachments available on primary | url
-| geo_attachments_synced | Gauge | 10.2 | Number of attachments synced on secondary | url
-| geo_attachments_failed | Gauge | 10.2 | Number of attachments failed to sync on secondary | url
-| geo_last_event_id | Gauge | 10.2 | Database ID of the latest event log entry on the primary | url
-| geo_last_event_timestamp | Gauge | 10.2 | UNIX timestamp of the latest event log entry on the primary | url
-| geo_cursor_last_event_id | Gauge | 10.2 | Last database ID of the event log processed by the secondary | url
-| geo_cursor_last_event_timestamp | Gauge | 10.2 | Last UNIX timestamp of the event log processed by the secondary | url
-| geo_status_failed_total | Counter | 10.2 | Number of times retrieving the status from the Geo Node failed | url
-| geo_last_successful_status_check_timestamp | Gauge | 10.2 | Last timestamp when the status was successfully updated | url
-| geo_lfs_objects_synced_missing_on_primary | Gauge | 10.7 | Number of LFS objects marked as synced due to the file missing on the primary | url
-| geo_job_artifacts_synced_missing_on_primary | Gauge | 10.7 | Number of job artifacts marked as synced due to the file missing on the primary | url
-| geo_attachments_synced_missing_on_primary | Gauge | 10.7 | Number of attachments marked as synced due to the file missing on the primary | url
-| geo_repositories_checksummed_count | Gauge | 10.7 | Number of repositories checksummed on primary | url
-| geo_repositories_checksum_failed_count | Gauge | 10.7 | Number of repositories failed to calculate the checksum on primary | url
-| geo_wikis_checksummed_count | Gauge | 10.7 | Number of wikis checksummed on primary | url
-| geo_wikis_checksum_failed_count | Gauge | 10.7 | Number of wikis failed to calculate the checksum on primary | url
-| geo_repositories_verified_count | Gauge | 10.7 | Number of repositories verified on secondary | url
-| geo_repositories_verification_failed_count | Gauge | 10.7 | Number of repositories failed to verify on secondary | url
-| geo_repositories_checksum_mismatch_count | Gauge | 10.7 | Number of repositories that checksum mismatch on secondary | url
-| geo_wikis_verified_count | Gauge | 10.7 | Number of wikis verified on secondary | url
-| geo_wikis_verification_failed_count | Gauge | 10.7 | Number of wikis failed to verify on secondary | url
-| geo_wikis_checksum_mismatch_count | Gauge | 10.7 | Number of wikis that checksum mismatch on secondary | url
-| geo_repositories_checked_count | Gauge | 11.1 | Number of repositories that have been checked via `git fsck` | url
-| geo_repositories_checked_failed_count | Gauge | 11.1 | Number of repositories that have a failure from `git fsck` | url
-| geo_repositories_retrying_verification_count | Gauge | 11.2 | Number of repositories verification failures that Geo is actively trying to correct on secondary | url
-| geo_wikis_retrying_verification_count | Gauge | 11.2 | Number of wikis verification failures that Geo is actively trying to correct on secondary | url
+| Metric | Type | Since | Description | Labels |
+|:---------------------------------------------- |:------- |:----- |:----------- |:------ |
+| `geo_db_replication_lag_seconds` | Gauge | 10.2 | Database replication lag (seconds) | url |
+| `geo_repositories` | Gauge | 10.2 | Total number of repositories available on primary | url |
+| `geo_repositories_synced` | Gauge | 10.2 | Number of repositories synced on secondary | url |
+| `geo_repositories_failed` | Gauge | 10.2 | Number of repositories failed to sync on secondary | url |
+| `geo_lfs_objects` | Gauge | 10.2 | Total number of LFS objects available on primary | url |
+| `geo_lfs_objects_synced` | Gauge | 10.2 | Number of LFS objects synced on secondary | url |
+| `geo_lfs_objects_failed` | Gauge | 10.2 | Number of LFS objects failed to sync on secondary | url |
+| `geo_attachments` | Gauge | 10.2 | Total number of file attachments available on primary | url |
+| `geo_attachments_synced` | Gauge | 10.2 | Number of attachments synced on secondary | url |
+| `geo_attachments_failed` | Gauge | 10.2 | Number of attachments failed to sync on secondary | url |
+| `geo_last_event_id` | Gauge | 10.2 | Database ID of the latest event log entry on the primary | url |
+| `geo_last_event_timestamp` | Gauge | 10.2 | UNIX timestamp of the latest event log entry on the primary | url |
+| `geo_cursor_last_event_id` | Gauge | 10.2 | Last database ID of the event log processed by the secondary | url |
+| `geo_cursor_last_event_timestamp` | Gauge | 10.2 | Last UNIX timestamp of the event log processed by the secondary | url |
+| `geo_status_failed_total` | Counter | 10.2 | Number of times retrieving the status from the Geo Node failed | url |
+| `geo_last_successful_status_check_timestamp` | Gauge | 10.2 | Last timestamp when the status was successfully updated | url |
+| `geo_lfs_objects_synced_missing_on_primary` | Gauge | 10.7 | Number of LFS objects marked as synced due to the file missing on the primary | url |
+| `geo_job_artifacts_synced_missing_on_primary` | Gauge | 10.7 | Number of job artifacts marked as synced due to the file missing on the primary | url |
+| `geo_attachments_synced_missing_on_primary` | Gauge | 10.7 | Number of attachments marked as synced due to the file missing on the primary | url |
+| `geo_repositories_checksummed_count` | Gauge | 10.7 | Number of repositories checksummed on primary | url |
+| `geo_repositories_checksum_failed_count` | Gauge | 10.7 | Number of repositories failed to calculate the checksum on primary | url |
+| `geo_wikis_checksummed_count` | Gauge | 10.7 | Number of wikis checksummed on primary | url |
+| `geo_wikis_checksum_failed_count` | Gauge | 10.7 | Number of wikis failed to calculate the checksum on primary | url |
+| `geo_repositories_verified_count` | Gauge | 10.7 | Number of repositories verified on secondary | url |
+| `geo_repositories_verification_failed_count` | Gauge | 10.7 | Number of repositories failed to verify on secondary | url |
+| `geo_repositories_checksum_mismatch_count` | Gauge | 10.7 | Number of repositories that checksum mismatch on secondary | url |
+| `geo_wikis_verified_count` | Gauge | 10.7 | Number of wikis verified on secondary | url |
+| `geo_wikis_verification_failed_count` | Gauge | 10.7 | Number of wikis failed to verify on secondary | url |
+| `geo_wikis_checksum_mismatch_count` | Gauge | 10.7 | Number of wikis that checksum mismatch on secondary | url |
+| `geo_repositories_checked_count` | Gauge | 11.1 | Number of repositories that have been checked via `git fsck` | url |
+| `geo_repositories_checked_failed_count` | Gauge | 11.1 | Number of repositories that have a failure from `git fsck` | url |
+| `geo_repositories_retrying_verification_count` | Gauge | 11.2 | Number of repositories verification failures that Geo is actively trying to correct on secondary | url |
+| `geo_wikis_retrying_verification_count` | Gauge | 11.2 | Number of wikis verification failures that Geo is actively trying to correct on secondary | url |
### Ruby metrics
Some basic Ruby runtime metrics are available:
-| Metric | Type | Since | Description |
-|:-------------------------------------- |:--------- |:----- |:----------- |
-| ruby_gc_duration_seconds | Counter | 11.1 | Time spent by Ruby in GC |
-| ruby_gc_stat_... | Gauge | 11.1 | Various metrics from [GC.stat] |
-| ruby_file_descriptors | Gauge | 11.1 | File descriptors per process |
-| ruby_memory_bytes | Gauge | 11.1 | Memory usage by process |
-| ruby_sampler_duration_seconds | Counter | 11.1 | Time spent collecting stats |
-| ruby_process_cpu_seconds_total | Gauge | 12.0 | Total amount of CPU time per process |
-| ruby_process_max_fds | Gauge | 12.0 | Maximum number of open file descriptors per process |
-| ruby_process_resident_memory_bytes | Gauge | 12.0 | Memory usage by process, measured in bytes |
-| ruby_process_start_time_seconds | Gauge | 12.0 | UNIX timestamp of process start time |
+| Metric | Type | Since | Description |
+|:------------------------------------ |:--------- |:----- |:----------- |
+| `ruby_gc_duration_seconds` | Counter | 11.1 | Time spent by Ruby in GC |
+| `ruby_gc_stat_...` | Gauge | 11.1 | Various metrics from [GC.stat] |
+| `ruby_file_descriptors` | Gauge | 11.1 | File descriptors per process |
+| `ruby_memory_bytes` | Gauge | 11.1 | Memory usage by process |
+| `ruby_sampler_duration_seconds` | Counter | 11.1 | Time spent collecting stats |
+| `ruby_process_cpu_seconds_total` | Gauge | 12.0 | Total amount of CPU time per process |
+| `ruby_process_max_fds` | Gauge | 12.0 | Maximum number of open file descriptors per process |
+| `ruby_process_resident_memory_bytes` | Gauge | 12.0 | Memory usage by process, measured in bytes |
+| `ruby_process_start_time_seconds` | Gauge | 12.0 | UNIX timestamp of process start time |
[GC.stat]: https://ruby-doc.org/core-2.6.3/GC.html#method-c-stat
@@ -183,28 +183,28 @@ Some basic Ruby runtime metrics are available:
Unicorn specific metrics, when Unicorn is used.
-| Metric | Type | Since | Description |
-|:---------------------------|:------|:------|:---------------------------------------------------|
-| unicorn_active_connections | Gauge | 11.0 | The number of active Unicorn connections (workers) |
-| unicorn_queued_connections | Gauge | 11.0 | The number of queued Unicorn connections |
-| unicorn_workers | Gauge | 12.0 | The number of Unicorn workers |
+| Metric | Type | Since | Description |
+|:-----------------------------|:------|:------|:---------------------------------------------------|
+| `unicorn_active_connections` | Gauge | 11.0 | The number of active Unicorn connections (workers) |
+| `unicorn_queued_connections` | Gauge | 11.0 | The number of queued Unicorn connections |
+| `unicorn_workers` | Gauge | 12.0 | The number of Unicorn workers |
## Puma Metrics **(EXPERIMENTAL)**
-When Puma is used instead of Unicorn, following metrics are available:
-
-| Metric | Type | Since | Description |
-|:-------------------------------------------- |:------- |:----- |:----------- |
-| puma_workers | Gauge | 12.0 | Total number of workers |
-| puma_running_workers | Gauge | 12.0 | Number of booted workers |
-| puma_stale_workers | Gauge | 12.0 | Number of old workers |
-| puma_running | Gauge | 12.0 | Number of running threads |
-| puma_queued_connections | Gauge | 12.0 | Number of connections in that worker's "todo" set waiting for a worker thread |
-| puma_active_connections | Gauge | 12.0 | Number of threads processing a request |
-| puma_pool_capacity | Gauge | 12.0 | Number of requests the worker is capable of taking right now |
-| puma_max_threads | Gauge | 12.0 | Maximum number of worker threads |
-| puma_idle_threads | Gauge | 12.0 | Number of spawned threads which are not processing a request |
-| puma_killer_terminations_total | Gauge | 12.0 | Number of workers terminated by PumaWorkerKiller |
+When Puma is used instead of Unicorn, the following metrics are available:
+
+| Metric | Type | Since | Description |
+|:---------------------------------------------- |:------- |:----- |:----------- |
+| `puma_workers` | Gauge | 12.0 | Total number of workers |
+| `puma_running_workers` | Gauge | 12.0 | Number of booted workers |
+| `puma_stale_workers` | Gauge | 12.0 | Number of old workers |
+| `puma_running` | Gauge | 12.0 | Number of running threads |
+| `puma_queued_connections` | Gauge | 12.0 | Number of connections in that worker's "todo" set waiting for a worker thread |
+| `puma_active_connections` | Gauge | 12.0 | Number of threads processing a request |
+| `puma_pool_capacity` | Gauge | 12.0 | Number of requests the worker is capable of taking right now |
+| `puma_max_threads` | Gauge | 12.0 | Maximum number of worker threads |
+| `puma_idle_threads` | Gauge | 12.0 | Number of spawned threads which are not processing a request |
+| `puma_killer_terminations_total` | Gauge | 12.0 | Number of workers terminated by PumaWorkerKiller |
## Metrics shared directory
@@ -221,9 +221,3 @@ If GitLab is installed using Omnibus and `tmpfs` is available then metrics
directory will be automatically configured.
[← Back to the main Prometheus page](index.md)
-
-[29118]: https://gitlab.com/gitlab-org/gitlab-ce/issues/29118
-[Prometheus]: https://prometheus.io
-[restart]: ../../restart_gitlab.md#omnibus-gitlab-restart
-[whitelist]: ../ip_whitelist.md
-[reconfigure]: ../../restart_gitlab.md#omnibus-gitlab-reconfigure
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index 142bcc65561..3ee8673b297 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -82,19 +82,17 @@ by another folder with the next 2 characters. They are both stored in a special
> [Introduced](https://gitlab.com/gitlab-org/gitaly/issues/1606) in GitLab 12.1.
-Forks of public projects are deduplicated by creating a third repository, the object pool, containing the objects from the source project. Using `objects/info/alternates`, the source project and forks use the object pool for shared objects. Objects are moved from the source project to the object pool when housekeeping is run on the source project.
+Forks of public projects are deduplicated by creating a third repository, the
+object pool, containing the objects from the source project. Using
+`objects/info/alternates`, the source project and forks use the object pool for
+shared objects. Objects are moved from the source project to the object pool
+when housekeeping is run on the source project.
```ruby
# object pool paths
"@pools/#{hash[0..1]}/#{hash[2..3]}/#{hash}.git"
```
-Object pools can be disabled using the `object_pools` feature flag, and can be
-disabled for individual projects by executing
-`Feature.disable(:object_pools, Project.find(<id>))`. Disabling object pools
-will not change existing deduplicated forks, but will prevent new forks from
-being deduplicated.
-
DANGER: **Danger:**
Do not run `git prune` or `git gc` in pool repositories! This can
cause data loss in "real" repositories that depend on the pool in
diff --git a/doc/administration/smime_signing_email.md b/doc/administration/smime_signing_email.md
index 9f719088f25..b2e3bf8487b 100644
--- a/doc/administration/smime_signing_email.md
+++ b/doc/administration/smime_signing_email.md
@@ -22,7 +22,7 @@ email_smime:
```
- Both files must be provided PEM-encoded.
-- The key file must be unencrypted so that Gitlab can read it without user
+- The key file must be unencrypted so that Gitlab can read it without user
intervention.
NOTE: **Note:** Be mindful of the access levels for your private keys and visibility to
diff --git a/doc/api/events.md b/doc/api/events.md
index 6dca8e52f69..1cd7047b867 100644
--- a/doc/api/events.md
+++ b/doc/api/events.md
@@ -70,7 +70,7 @@ Parameters:
Example request:
-```
+```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
```
@@ -275,7 +275,7 @@ Parameters:
Example request:
-```
+```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:project_id/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
```
@@ -343,8 +343,8 @@ Example response:
"username": "root",
"id": 1,
"state": "active",
- "avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png",
- "web_url": "http://localhost:3000/root"
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/1/fox_avatar.png",
+ "web_url": "https://gitlab.example.com/root"
},
"created_at": "2015-12-04T10:33:56.698Z",
"system": false,
@@ -357,8 +357,8 @@ Example response:
"username": "root",
"id": 1,
"state": "active",
- "avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png",
- "web_url": "http://localhost:3000/root"
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/1/fox_avatar.png",
+ "web_url": "https://gitlab.example.com/root"
},
"author_username": "root"
}
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 8313dd2c3bd..cadc9291489 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -284,7 +284,6 @@ Example response:
"award_emoji":"http://example.com/api/v4/projects/4/issues/41/award_emoji",
"project":"http://example.com/api/v4/projects/4"
},
- "subscribed": false,
"task_completion_status":{
"count":0,
"completed_count":0
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 9f392418153..cf28ea84704 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -852,10 +852,10 @@ Get the users list of a project.
GET /projects/:id/users
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `search` | string | no | Search for specific users |
-| `skip_users` | array[int] | no | Filter out users with the specified IDs |
+| Attribute | Type | Required | Description |
+| ------------ | ------------- | -------- | ----------- |
+| `search` | string | no | Search for specific users |
+| `skip_users` | integer array | no | Filter out users with the specified IDs |
```json
[
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index f8151e3e18c..a59a0477b80 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -172,6 +172,29 @@ job:
cache: {}
```
+### Inherit global config, but override specific settings per job
+
+You can override cache settings without overwriting the global cache by using
+[anchors](../yaml/README.md#anchors). For example, if you want to override the
+`policy` for one job:
+
+```yaml
+cache: &global_cache
+ key: ${CI_COMMIT_REF_SLUG}
+ paths:
+ - node_modules/
+ - public/
+ - vendor/
+ policy: pull-push
+
+job:
+ cache:
+ # inherit all global cache settings
+ <<: *global_cache
+ # override the policy
+ policy: pull
+```
+
For more fine tuning, read also about the
[`cache: policy`](../yaml/README.md#cachepolicy).
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 89a61b2a9e3..5237c61f191 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -100,6 +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 coniditions to evaluate and determine selected attributes of a build 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`. |
@@ -386,7 +387,7 @@ In addition, `only` and `except` allow the use of special keywords:
| `triggers` | For pipelines created using a trigger token. |
| `web` | For pipelines created using **Run pipeline** button in GitLab UI (under your project's **Pipelines**). |
| `merge_requests` | When a merge request is created or updated (See [pipelines for merge requests](../merge_request_pipelines/index.md)). |
-| `chats` | For jobs created using a [GitLab ChatOps](../chatops/README.md) command. |
+| `chat` | For jobs created using a [GitLab ChatOps](../chatops/README.md) command. |
In the example below, `job` will run only for refs that start with `issue-`,
whereas all branches will be skipped:
@@ -690,6 +691,125 @@ In the scenario above, if a merge request is created or updated that changes
either files in `service-one` directory or the `Dockerfile`, GitLab creates
and triggers the `docker build service one` job.
+### `rules`
+
+Using `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)).
+
+For example, using `if`:
+
+```yaml
+job:
+ script: "echo Hello, Rules!"
+ rules:
+ - if: '$CI_MERGE_REQUEST_TARGET_BRANCH == "master"' # This rule will be evaluated
+ when: always
+ - if: '$VAR =~ /pattern/' # This rule will only be evaluated if the first does not match
+ 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"
+```
+
+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.
+
+#### `rules:if`
+
+`rules:if` differs slightly from `only:variables` by accepting only a single
+expression string, rather than an array of them. Any set of expressions to be
+evaluated should be conjoined into a single expression using `&&` or `||`. For example:
+
+```yaml
+job:
+ script: "echo Hello, Rules!"
+ rules:
+ - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH =~ /^feature/ && $CI_MERGE_REQUEST_TARGET_BRANCH == "master"' # This rule will be evaluated
+ when: always
+ - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH =~ /^feature/' # This rule will only be evaluated if the target branch is not "master"
+ when: manual
+ - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH' # If neither of the first two match but the simple presence does, we set to "on_success" by default
+```
+
+If none of the provided rules match, the job will be set to `when:never`, and
+not included in the pipeline. If `rules:when` is not included in the configuration
+at all, the behavior defaults to `job:when`, which continues to default to
+`on_success`.
+
+#### `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.
+
+```yaml
+docker build:
+ script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
+ rules:
+ - changes: # Will include the job and set to when:manual if any of the follow paths match a modified file.
+ - Dockerfile
+ when: manual
+ - if: '$VAR == "string value"'
+ when: manual # Will include the job and set to when:manual if the expression evaluates to true, after the `changes:` rule fails to match.
+ - when: on_success # If neither of the first rules match, set to on_success
+
+```
+
+#### 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.
+
+```yaml
+docker build:
+ script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
+ rules:
+ - if: '$VAR == "string value"'
+ changes: # Will include the job and set to when:manual if any of the follow paths match a modified file.
+ - Dockerfile
+ - docker/scripts/*
+ when: manual
+ # - 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.
+
+#### 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`.
+
+Delayed jobs require a `start_in` value, so rule objects do as well. For example:
+
+```yaml
+docker build:
+ script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
+ rules:
+ - changes: # Will include the job and delay 3 hours when the Dockerfile has changed
+ - Dockerfile
+ when: delayed
+ start_in: '3 hours'
+ - when: on_success # Otherwise include the job and set to run normally
+
+```
+
+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).
+
### `tags`
`tags` is used to select specific Runners from the list of all Runners that are
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index bd07a01e782..814624c7586 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -35,6 +35,7 @@ the `author` field. GitLab team members **should not**.
- Any user-facing change **should** have a changelog entry. Example: "GitLab now
uses system fonts for all text."
+- Any docs-only changes **should not** have a changelog entry.
- Any change behind a feature flag **should not** have a changelog entry. The entry should be added [in the merge request removing the feature flags](feature_flags/development.md).
- A fix for a regression introduced and then fixed in the same release (i.e.,
fixing a bug introduced during a monthly release candidate) **should not**
diff --git a/doc/development/documentation/feature-change-workflow.md b/doc/development/documentation/feature-change-workflow.md
index ac93ada5a4b..00c76fe0f1b 100644
--- a/doc/development/documentation/feature-change-workflow.md
+++ b/doc/development/documentation/feature-change-workflow.md
@@ -69,7 +69,7 @@ To follow a consistent workflow every month, documentation changes
involve the Product Managers, the developer who shipped the feature,
and the technical writer for the DevOps stage. Each role is described below.
-The Documentation items in the GitLab CE/EE [Feature Proposal issue template](https://gitlab.com/gitlab-org/gitlab-ce/raw/template-improvements-for-documentation/.gitlab/issue_templates/Feature%20proposal.md)
+The Documentation items in the GitLab CE/EE [Feature Proposal issue template](https://gitlab.com/gitlab-org/gitlab-ce/raw/master/.gitlab/issue_templates/Feature%20proposal.md)
and default merge request template will assist you with following this process.
### Product Manager role
diff --git a/doc/development/emails.md b/doc/development/emails.md
index edec0f86989..5676c3b32f4 100644
--- a/doc/development/emails.md
+++ b/doc/development/emails.md
@@ -6,7 +6,7 @@ To view rendered emails "sent" in your development instance, visit
[`/rails/letter_opener`](http://localhost:3000/rails/letter_opener).
Please note that [S/MIME signed](../administration/smime_signing_email.md) emails
-[cannot be currently previewed](https://github.com/fgrehm/letter_opener_web/issues/96) with
+[cannot be currently previewed](https://github.com/fgrehm/letter_opener_web/issues/96) with
`letter_opener`.
## Mailer previews
diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md
index 5ce59891afa..8d32d0314ae 100644
--- a/doc/development/git_object_deduplication.md
+++ b/doc/development/git_object_deduplication.md
@@ -8,30 +8,6 @@ storage disk use. To counteract this problem, we are adding Git object
deduplication for forks to GitLab. In this document, we will describe how
GitLab implements Git object deduplication.
-## Enabling Git object deduplication via feature flags
-
-As of GitLab 12.0, Git object deduplication in GitLab is still behind a
-feature flag. In this document, you can read about the effects of
-enabling the feature. Also, note that Git object deduplication is
-limited to forks of public projects on hashed repository storage.
-
-You can enable deduplication globally by setting the `object_pools`
-feature flag to `true`:
-
-``` {.ruby}
-Feature.enable(:object_pools)
-```
-
-Or just for forks of a specific project:
-
-``` {.ruby}
-fork_parent = Project.find(MY_PROJECT_ID)
-Feature.enable(:object_pools, fork_parent)
-```
-
-To check if a project uses Git object deduplication, look in a Rails
-console if `project.pool_repository` is present.
-
## Pool repositories
### Understanding Git alternates
diff --git a/doc/development/namespaces_storage_statistics.md b/doc/development/namespaces_storage_statistics.md
index b3285de4705..2c7e5935435 100644
--- a/doc/development/namespaces_storage_statistics.md
+++ b/doc/development/namespaces_storage_statistics.md
@@ -20,8 +20,8 @@ every time the project is saved.
The summary of those statistics per namespace is then retrieved
by [`Namespaces#with_statistics`](https://gitlab.com/gitlab-org/gitlab-ce/blob/v12.2.0.pre/app/models/namespace.rb#L70) scope. Analyzing this query we noticed that:
-* It takes up to `1.2` seconds for namespaces with over `15k` projects.
-* It can't be analyzed with [ChatOps](chatops_on_gitlabcom.md), as it times out.
+- It takes up to `1.2` seconds for namespaces with over `15k` projects.
+- It can't be analyzed with [ChatOps](chatops_on_gitlabcom.md), as it times out.
Additionally, the pattern that is currently used to update the project statistics
(the callback) doesn't scale adequately. It is currently one of the largest
@@ -62,8 +62,8 @@ REFRESH MATERIALIZED VIEW root_namespace_storage_statistics;
While this implied a single query update (and probably a fast one), it has some downsides:
-* Materialized views syntax varies from PostgreSQL and MySQL. While this feature was worked on, MySQL was still supported by GitLab.
-* Rails does not have native support for materialized views. We'd need to use a specialized gem to take care of the management of the database views, which implies additional work.
+- Materialized views syntax varies from PostgreSQL and MySQL. While this feature was worked on, MySQL was still supported by GitLab.
+- Rails does not have native support for materialized views. We'd need to use a specialized gem to take care of the management of the database views, which implies additional work.
### Attempt B: An update through a CTE
@@ -131,8 +131,8 @@ WHERE namespace_id IN (
Even though this approach would make aggregating much easier, it has some major downsides:
-* We'd have to migrate **all namespaces** by adding and filling a new column. Because of the size of the table, dealing with time/cost will not be great. The background migration will take approximately `153h`, see <https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29772>.
-* Background migration has to be shipped one release before, delaying the functionality by another milestone.
+- We'd have to migrate **all namespaces** by adding and filling a new column. Because of the size of the table, dealing with time/cost will not be great. The background migration will take approximately `153h`, see <https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29772>.
+- Background migration has to be shipped one release before, delaying the functionality by another milestone.
### Attempt E (final): Update the namespace storage statistics in async way
@@ -155,10 +155,10 @@ but we refresh them through Sidekiq jobs and in different transactions:
This implementation has the following benefits:
-* All the updates are done async, so we're not increasing the length of the transactions for `project_statistics`.
-* We're doing the update in a single SQL query.
-* It is compatible with PostgreSQL and MySQL.
-* No background migration required.
+- All the updates are done async, so we're not increasing the length of the transactions for `project_statistics`.
+- We're doing the update in a single SQL query.
+- It is compatible with PostgreSQL and MySQL.
+- No background migration required.
The only downside of this approach is that namespaces' statistics are updated up to `1.5` hours after the change is done,
which means there's a time window in which the statistics are inaccurate. Because we're still not
@@ -171,8 +171,8 @@ performant approach of aggregating the root namespaces.
All the details regarding this use case can be found on:
-* <https://gitlab.com/gitlab-org/gitlab-ce/issues/62214>
-* Merge Request with the implementation: <https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/28996>
+- <https://gitlab.com/gitlab-org/gitlab-ce/issues/62214>
+- Merge Request with the implementation: <https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/28996>
Performance of the namespace storage statistics were measured in staging and production (GitLab.com). All results were posted
on <https://gitlab.com/gitlab-org/gitlab-ce/issues/64092>: No problem has been reported so far.
diff --git a/doc/development/uploads.md b/doc/development/uploads.md
index 234539bb673..681ce9d9fe8 100644
--- a/doc/development/uploads.md
+++ b/doc/development/uploads.md
@@ -174,14 +174,14 @@ sequenceDiagram
c ->>+w: POST /some/url/upload
w->>+s: save the incoming file on a temporary location
- s-->>-w:
+ s-->>-w:
w->>+r: POST /some/url/upload
Note over w,r: file was replaced with its location<br>and other metadata
opt requires async processing
r->>+redis: schedule a job
- redis-->>-r:
+ redis-->>-r:
end
r-->>-c: request result
@@ -230,17 +230,17 @@ sequenceDiagram
w->>+os: PUT file
Note over w,os: file is stored on a temporary location. Rails select the destination
- os-->>-w:
+ os-->>-w:
w->>+r: POST /some/url/upload
Note over w,r: file was replaced with its location<br>and other metadata
r->>+os: move object to final destination
- os-->>-r:
+ os-->>-r:
opt requires async processing
r->>+redis: schedule a job
- redis-->>-r:
+ redis-->>-r:
end
r-->>-c: request result
@@ -268,4 +268,3 @@ sequenceDiagram
This option affect the response to the `/authorize` call. When not enabled, the API response will not contain presigned URLs and workhorse will write the file the shared disk, on the path is provided by rails, acting like object storage was disabled.
Once the request reachs rails, it will schedule an object storage upload as a sidekiq job.
-
diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md
index 5de173abbff..a289b90b81b 100644
--- a/doc/gitlab-basics/start-using-git.md
+++ b/doc/gitlab-basics/start-using-git.md
@@ -102,7 +102,7 @@ files to your local computer, automatically preserving the Git connection with t
remote repository.
You can either clone it via HTTPS or [SSH](../ssh/README.md). If you chose to clone
-it via HTTPS, you'll have to enter your credentials every time you pull and push. You can read more about credential storage in the [Git Credentials documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage). With SSH, you enter your credentials only once.
+it via HTTPS, you'll have to enter your credentials every time you pull and push. You can read more about credential storage in the [Git Credentials documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage). With SSH, you enter your credentials only once.
You can find both paths (HTTPS and SSH) by navigating to your project's landing page
and clicking **Clone**. GitLab will prompt you with both paths, from which you can copy
@@ -157,7 +157,7 @@ git pull <REMOTE> <name-of-branch>
When you clone a repository, `REMOTE` is typically `origin`. This is where the
repository was cloned from, and it indicates the SSH or HTTPS URL of the repository
on the remote server. `<name-of-branch>` is usually `master`, but it may be any existing
-branch. You can create additional named remotes and branches as necessary.
+branch. You can create additional named remotes and branches as necessary.
You can learn more on how Git manages remote repositories in the [Git Remote documentation](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes).
@@ -169,7 +169,7 @@ To view your remote repositories, type:
git remote -v
```
-The `-v` flag stands for verbose.
+The `-v` flag stands for verbose.
### Add a remote repository
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 7a92ed994c7..0314b5a808d 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -277,3 +277,24 @@ omniauth:
sync_profile_from_provider: ['twitter', 'google_oauth2']
sync_profile_attributes: ['email', 'location']
```
+
+## Bypassing two factor authentication
+
+Starting with GitLab 12.3, this allows users to login with the specified
+providers without two factor authentication.
+
+Define the allowed providers using an array, e.g. `["twitter", 'google_oauth2']`, or as
+`true`/`false` to allow all providers or none. This option should only be configured
+for providers which already have two factor authentication (default: false).
+This configration dose not apply to SAML.
+
+```ruby
+gitlab_rails['omniauth_allow_bypass_two_factor'] = ['twitter', 'google_oauth2']
+```
+
+**For installations from source**
+
+```yaml
+omniauth:
+ allow_bypass_two_factor: ['twitter', 'google_oauth2']
+```
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index b4b7d711d5a..19486052dd9 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -923,6 +923,29 @@ backup beforehand.
UPDATE ci_runners SET token = null, token_encrypted = null;
```
+#### Reset pending pipeline jobs
+
+1. Enter the DB console:
+
+ For Omnibus GitLab packages:
+
+ ```sh
+ sudo gitlab-rails dbconsole
+ ```
+
+ For installations from source:
+
+ ```sh
+ sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
+ ```
+
+1. Clear all the tokens for pending jobs:
+
+ ```sql
+ -- Clear build tokens
+ UPDATE ci_builds SET token = null, token_encrypted = null;
+ ```
+
A similar strategy can be employed for the remaining features - by removing the
data that cannot be decrypted, GitLab can be brought back into working order,
and the lost data can be manually replaced.
diff --git a/doc/security/README.md b/doc/security/README.md
index 5d498ac7602..e3fb07c69c2 100644
--- a/doc/security/README.md
+++ b/doc/security/README.md
@@ -5,6 +5,7 @@ type: index
# Security
+- [Password storage](password_storage.md)
- [Password length limits](password_length_limits.md)
- [Restrict SSH key technologies and minimum length](ssh_keys_restrictions.md)
- [Rate limits](rate_limits.md)
diff --git a/doc/security/password_storage.md b/doc/security/password_storage.md
new file mode 100644
index 00000000000..f4e32f96f7b
--- /dev/null
+++ b/doc/security/password_storage.md
@@ -0,0 +1,13 @@
+---
+type: reference
+---
+
+# Password Storage
+
+GitLab stores user passwords in a hashed format, to prevent passwords from being visible.
+
+GitLab uses the [Devise](https://github.com/plataformatec/devise) authentication library, which handles the hashing of user passwords. Password hashes are created with the following attributes:
+
+- **Hashing**: the [bcrypt](https://en.wikipedia.org/wiki/Bcrypt) hashing function is used to generate the hash of the provided password. This is a strong, industry-standard cryptographic hashing function.
+- **Stretching**: Password hashes are [stretched](https://en.wikipedia.org/wiki/Key_stretching) to harden against brute-force attacks. GitLab uses a stretching factor of 10 by default.
+- **Salting**: A [cryptographic salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) is added to each password to harden against pre-computed hash and dictionary attacks. Each salt is randomly generated for each password, so that no two passwords share a salt, to further increase security.
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 26d5221acc5..6021e8cff1d 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -111,9 +111,8 @@ To make full use of Auto DevOps, you will need:
a domain configured with wildcard DNS which is going to be used by all of your
Auto DevOps applications. [Read the specifics](#auto-devops-base-domain).
- **Kubernetes** (needed for Auto Review Apps, Auto Deploy, and Auto Monitoring) -
- To enable deployments, you will need Kubernetes 1.5+. You need a [Kubernetes cluster][kubernetes-clusters]
- for the project, or a Kubernetes [default service template](../../user/project/integrations/services_templates.md)
- for the entire GitLab installation.
+ To enable deployments, you will need Kubernetes 1.5+. You will need a [Kubernetes cluster][kubernetes-clusters]
+ for the project.
- **A load balancer** - You can use NGINX ingress by deploying it to your
Kubernetes cluster using the
[`nginx-ingress`](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress)
diff --git a/doc/user/admin_area/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md
index a3f4bc774ce..52f24c602df 100644
--- a/doc/user/admin_area/monitoring/health_check.md
+++ b/doc/user/admin_area/monitoring/health_check.md
@@ -28,14 +28,6 @@ With default whitelist settings, the probes can be accessed from localhost using
```text
GET http://localhost/-/health
```
-```text
-GET http://localhost/-/readiness
-```
-```text
-GET http://localhost/-/liveness
-```text
-GET http://localhost/-/health
-```
```text
GET http://localhost/-/readiness
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 86491c7d74e..7b631a5a1cd 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -94,6 +94,36 @@ If you want to whitelist some specific vulnerabilities, you can do so by definin
them in a YAML file named `clair-whitelist.yml`. Read more in the
[Clair documentation](https://github.com/arminc/clair-scanner/blob/master/README.md#example-whitelist-yaml-file).
+## Example
+
+The following is a sample `.gitlab-ci.yml` that will build your Docker Image, push it to the container registry and run Container Scanning.
+
+```yaml
+variables:
+ DOCKER_DRIVER: overlay2
+
+services:
+ - docker:stable-dind
+
+stages:
+ - build
+ - test
+
+include:
+ - template: Container-Scanning.gitlab-ci.yml
+
+build:
+ image: docker:stable
+ stage: build
+ variables:
+ IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
+ script:
+ - docker info
+ - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
+ - docker build -t $IMAGE .
+ - docker push $IMAGE
+```
+
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
@@ -125,4 +155,4 @@ docker: Error response from daemon: failed to copy xattrs: failed to set xattr "
This is a result of a bug in Docker which is now [fixed](https://github.com/containerd/continuity/pull/138 "fs: add WithAllowXAttrErrors CopyOpt").
To prevent the error, ensure the Docker version that the Runner is using is
`18.09.03` or higher. For more information, see
-[issue #10241](https://gitlab.com/gitlab-org/gitlab-ee/issues/10241 "Investigate why Container Scanning is not working with NFS mounts").
+[issue #10241](https://gitlab.com/gitlab-org/gitlab-ee/issues/10241 "Investigate why Container Scanning is not working with NFS mounts"). \ No newline at end of file
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 3148ec63c79..b40392e12d5 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -141,22 +141,22 @@ dependency_scanning:
Dependency Scanning can be [configured](#customizing-the-dependency-scanning-settings)
using environment variables.
-| Environment variable | Function |
-|-------------------------------- |----------|
-| `DS_ANALYZER_IMAGES` | Comma separated list of custom images. The official default images are still enabled. Read more about [customizing analyzers](analyzers.md). |
-| `DS_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
-| `DS_ANALYZER_IMAGE_TAG` | Override the Docker tag of the official default images. Read more about [customizing analyzers](analyzers.md). |
-| `DS_PYTHON_VERSION` | Version of Python. If set to 2, dependencies are installed using Python 2.7 instead of Python 3.6. ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12296) in GitLab 12.1)|
-| `DS_PIP_DEPENDENCY_PATH` | Path to load Python pip dependencies from. ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12412) in GitLab 12.2) |
-| `DS_DEFAULT_ANALYZERS` | Override the names of the official default images. Read more about [customizing analyzers](analyzers.md). |
-| `DS_DISABLE_REMOTE_CHECKS` | Do not send any data to GitLab. Used in the [Gemnasium analyzer](#remote-checks). |
-| `DS_PULL_ANALYZER_IMAGES` | Pull the images from the Docker registry (set to `0` to disable). |
-| `DS_EXCLUDED_PATHS` | Exclude vulnerabilities from output based on the paths. A comma-separated list of patterns. Patterns can be globs, file or folder paths. Parent directories will also match patterns. |
-| `DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT` | Time limit for Docker client negotiation. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. |
-| `DS_PULL_ANALYZER_IMAGE_TIMEOUT` | Time limit when pulling the image of an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. |
-| `DS_RUN_ANALYZER_TIMEOUT` | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. |
-| `PIP_INDEX_URL` | Base URL of Python Package Index (default `https://pypi.org/simple`). |
-| `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. |
+| Environment variable | Description | Example usage |
+|-------------------------------- |-------------| |
+| `DS_ANALYZER_IMAGES` | Comma separated list of custom images. The official default images are still enabled. Read more about [customizing analyzers](analyzers.md). | |
+| `DS_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). | |
+| `DS_ANALYZER_IMAGE_TAG` | Override the Docker tag of the official default images. Read more about [customizing analyzers](analyzers.md). | |
+| `DS_PYTHON_VERSION` | Version of Python. If set to 2, dependencies are installed using Python 2.7 instead of Python 3.6. ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12296) in GitLab 12.1)| |
+| `DS_PIP_DEPENDENCY_PATH` | Path to load Python pip dependencies from. ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12412) in GitLab 12.2) | |
+| `DS_DEFAULT_ANALYZERS` | Override the names of the official default images. Read more about [customizing analyzers](analyzers.md). | |
+| `DS_DISABLE_REMOTE_CHECKS` | Do not send any data to GitLab. Used in the [Gemnasium analyzer](#remote-checks). | |
+| `DS_PULL_ANALYZER_IMAGES` | Pull the images from the Docker registry (set to `0` to disable). | |
+| `DS_EXCLUDED_PATHS` | Exclude vulnerabilities from output based on the paths. A comma-separated list of patterns. Patterns can be globs, file or folder paths. Parent directories will also match patterns. | `DS_EXCLUDED_PATHS=doc,spec` |
+| `DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT` | Time limit for Docker client negotiation. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | |
+| `DS_PULL_ANALYZER_IMAGE_TIMEOUT` | Time limit when pulling the image of an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | |
+| `DS_RUN_ANALYZER_TIMEOUT` | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | |
+| `PIP_INDEX_URL` | Base URL of Python Package Index (default `https://pypi.org/simple`). | |
+| `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. | |
## Reports JSON format
@@ -276,8 +276,8 @@ it highlighted:
Here is the description of the report file structure nodes and their meaning. All fields are mandatory to be present in
the report JSON unless stated otherwise. Presence of optional fields depends on the underlying analyzers being used.
-| Report JSON node | Function |
-|------------------------------------------------------|----------|
+| Report JSON node | Description |
+|------------------------------------------------------|-------------|
| `version` | Report syntax version used to generate this JSON. |
| `vulnerabilities` | Array of vulnerability objects. |
| `vulnerabilities[].category` | Where this vulnerability belongs (SAST, Dependency Scanning etc.). For Dependency Scanning, it will always be `dependency_scanning`. |
diff --git a/doc/user/application_security/license_management/index.md b/doc/user/application_security/license_management/index.md
index 912f2f0e209..44b2671930e 100644
--- a/doc/user/application_security/license_management/index.md
+++ b/doc/user/application_security/license_management/index.md
@@ -169,9 +169,9 @@ If you still need to run tests during `mvn install`, add `-DskipTests=false` to
> [Introduced](https://gitlab.com/gitlab-org/security-products/license-management/merge_requests/36) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
-License Compliance uses Python 2.7 and pip 10.0 by default.
-If your project requires Python 3, you can switch to Python 3.5 and pip 19.1
-by setting the `LM_PYTHON_VERSION` environment variable to `3`.
+License Compliance uses Python 3.5 and pip 19.1 by default.
+If your project requires Python 2, you can switch to Python 2.7 and pip 10.0
+by setting the `LM_PYTHON_VERSION` environment variable to `2`.
```yaml
include:
@@ -179,7 +179,7 @@ include:
license_management:
variables:
- LM_PYTHON_VERSION: 3
+ LM_PYTHON_VERSION: 2
```
## Project policies for License Compliance
diff --git a/doc/user/application_security/sast/analyzers.md b/doc/user/application_security/sast/analyzers.md
index f730a25a9fc..a1bd00f34e3 100644
--- a/doc/user/application_security/sast/analyzers.md
+++ b/doc/user/application_security/sast/analyzers.md
@@ -128,7 +128,7 @@ custom analyzer can scan the source code.
| Start column | ✓ | 𐄂 | 𐄂 | ✓ | ✓ | ✓ | ✓ | 𐄂 | ✓ | ✓ | ✓ | 𐄂 |
| End column | ✓ | 𐄂 | 𐄂 | ✓ | ✓ | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | ✓ | 𐄂 |
| External id (e.g. CVE) | 𐄂 | 𐄂 | ⚠ | 𐄂 | ⚠ | ✓ | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 |
-| URLs | ✓ | 𐄂 | ✓ | 𐄂 | ⚠ | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 |
+| URLs | ✓ | 𐄂 | ✓ | 𐄂 | ⚠ | 𐄂 | ⚠ | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 |
| Internal doc/explanation | ✓ | ⚠ | ✓ | 𐄂 | ✓ | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | ✓ |
| Solution | ✓ | 𐄂 | 𐄂 | 𐄂 | ⚠ | ✓ | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 | 𐄂 |
| Confidence | 𐄂 | ✓ | ✓ | 𐄂 | ✓ | ✓ | ✓ | 𐄂 | 𐄂 | 𐄂 | 𐄂 | ✓ |
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 2f15d997b5b..3eead6ccd3f 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -160,17 +160,21 @@ The following are Docker image-related variables.
Some analyzers make it possible to filter out vulnerabilities under a given threshold.
-| `SAST_BANDIT_EXCLUDED_PATHS` | - | comma-separated list of paths to exclude from scan. Uses Python's [`fnmatch` syntax](https://docs.python.org/2/library/fnmatch.html) |
-| `SAST_BRAKEMAN_LEVEL` | 1 | Ignore Brakeman vulnerabilities under given confidence level. Integer, 1=Low 3=High. |
-| `SAST_FLAWFINDER_LEVEL` | 1 | Ignore Flawfinder vulnerabilities under given risk level. Integer, 0=No risk, 5=High risk. |
-| `SAST_GITLEAKS_ENTROPY_LEVEL` | 8.0 | Minimum entropy for secret detection. Float, 0.0 = low, 8.0 = high. |
-| `SAST_GOSEC_LEVEL` | 0 | Ignore gosec vulnerabilities under given confidence level. Integer, 0=Undefined, 1=Low, 2=Medium, 3=High. |
-| `SAST_EXCLUDED_PATHS` | - | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, file or folder paths. Parent directories will also match patterns. |
+| Environment variable | Default value | Description | Example usage |
+|----------------------|---------------|-------------|---|
+| `SAST_BANDIT_EXCLUDED_PATHS` | - | comma-separated list of paths to exclude from scan. Uses Python's [`fnmatch` syntax](https://docs.python.org/2/library/fnmatch.html) | |
+| `SAST_BRAKEMAN_LEVEL` | 1 | Ignore Brakeman vulnerabilities under given confidence level. Integer, 1=Low 3=High. | |
+| `SAST_FLAWFINDER_LEVEL` | 1 | Ignore Flawfinder vulnerabilities under given risk level. Integer, 0=No risk, 5=High risk. | |
+| `SAST_GITLEAKS_ENTROPY_LEVEL` | 8.0 | Minimum entropy for secret detection. Float, 0.0 = low, 8.0 = high. | |
+| `SAST_GOSEC_LEVEL` | 0 | Ignore gosec vulnerabilities under given confidence level. Integer, 0=Undefined, 1=Low, 2=Medium, 3=High. | |
+| `SAST_EXCLUDED_PATHS` | - | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, file or folder paths. Parent directories will also match patterns. | `SAST_EXCLUDED_PATHS=doc,spec` |
### Timeouts
The following variables configure timeouts.
+| Environment variable | Default value | Description |
+|----------------------|---------------|-------------|
| `SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT` | 2m | Time limit for Docker client negotiation. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". For example, "300ms", "1.5h" or "2h45m". |
| `SAST_PULL_ANALYZER_IMAGE_TIMEOUT` | 5m | Time limit when pulling the image of an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". For example, "300ms", "1.5h" or "2h45m". |
| `SAST_RUN_ANALYZER_TIMEOUT` | 20m | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". For example, "300ms", "1.5h" or "2h45m".|
diff --git a/doc/user/index.md b/doc/user/index.md
index c93f64cd528..27e75189fc3 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -53,7 +53,7 @@ With GitLab Enterprise Edition, you can also:
- Improve collaboration with
[Merge Request Approvals](project/merge_requests/index.md#merge-request-approvals-starter),
[Multiple Assignees for Issues](project/issues/multiple_assignees_for_issues.md),
- and [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards-starter).
+ and [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards).
- Create formal relationships between issues with [Related Issues](project/issues/related_issues.md).
- Use [Burndown Charts](project/milestones/burndown_charts.md) to track progress during a sprint or while working on a new version of their software.
- Leverage [Elasticsearch](../integration/elasticsearch.md) with [Advanced Global Search](search/advanced_global_search.md) and [Advanced Syntax Search](search/advanced_search_syntax.md) for faster, more advanced code search across your entire GitLab instance.
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 932e7fd10b2..64c4066683b 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -17,7 +17,7 @@ When you create a project in GitLab, you'll have access to a large number of
- [Issue tracker](issues/index.md): Discuss implementations with your team within issues
- [Issue Boards](issue_board.md): Organize and prioritize your workflow
- - [Multiple Issue Boards](issue_board.md#multiple-issue-boards-starter): Allow your teams to create their own workflows (Issue Boards) for the same project **(STARTER)**
+ - [Multiple Issue Boards](issue_board.md#multiple-issue-boards): Allow your teams to create their own workflows (Issue Boards) for the same project
- [Repositories](repository/index.md): Host your code in a fully
integrated platform
- [Branches](repository/branches/index.md): use Git branching strategies to
@@ -34,7 +34,7 @@ When you create a project in GitLab, you'll have access to a large number of
- [Issue tracker](issues/index.md): Discuss implementations with your team within issues
- [Issue Boards](issue_board.md): Organize and prioritize your workflow
- - [Multiple Issue Boards](issue_board.md#multiple-issue-boards-starter): Allow your teams to create their own workflows (Issue Boards) for the same project **(STARTER)**
+ - [Multiple Issue Boards](issue_board.md#multiple-issue-boards): Allow your teams to create their own workflows (Issue Boards) for the same project
- [Merge Requests](merge_requests/index.md): Apply your branching
strategy and get reviewed by your team
- [Merge Request Approvals](merge_requests/merge_request_approvals.md): Ask for approval before
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index 9fc0ade809e..a80332adc46 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -194,7 +194,7 @@ The following tables outline the details of expected properties.
| Property | Type | Required | Description |
| ------ | ------ | ------ | ------- |
-| `type` | enum | no, defaults to `area-chart` | Specifies the chart type to use. |
+| `type` | enum | no, defaults to `area-chart` | Specifies the chart type to use, can be `area-chart` or `line-chart` |
| `title` | string | yes | Heading for the panel. |
| `y_label` | string | no, but highly encouraged | Y-Axis label for the panel. |
| `weight` | number | no, defaults to order in file | Order to appear within the grouping. Lower number means higher priority, which will be higher on the page. Numbers do not need to be consecutive. |
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index eaca5f8cfb8..519c02cf0ad 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -13,7 +13,7 @@ keeping everything in the same place, so that you don't need to jump
between different platforms to organize your workflow.
With GitLab Issue Boards, you organize your issues in lists that correspond to
-their assigned labels, visualizing issues designed as cards throughout that lists.
+their assigned labels, visualizing issues designed as cards throughout those lists.
You define your process and GitLab organizes it for you. You add your labels
then create the corresponding list to pull in your existing issues. When
@@ -27,12 +27,9 @@ Issue Boards** (version introduced in GitLab 8.11 - August 2016).
### Advanced features of Issue Boards
-With [GitLab Starter](https://about.gitlab.com/pricing/), you can create
-[multiple issue boards](#multiple-issue-boards-starter) for a given project. **(STARTER)**
-
-With [GitLab Premium](https://about.gitlab.com/pricing/), you can also create multiple
-issue boards for your groups, and add lists for [assignees](#assignee-lists-premium) and
-[milestones](#milestone-lists-premium). **(PREMIUM)**
+- Create multiple issue boards per project.
+- Create multiple issue boards per group. **(PREMIUM)**
+- Add lists for [assignees](#assignee-lists-premium) and [milestones](#milestone-lists-premium). **(PREMIUM)**
Check all the [advanced features of Issue Boards](#gitlab-enterprise-features-for-issue-boards)
below.
@@ -58,8 +55,7 @@ You create issues, host code, perform reviews, build, test,
and deploy from one single platform. Issue Boards help you to visualize
and manage the entire process _in_ GitLab.
-With [Multiple Issue Boards](#use-cases-for-multiple-issue-boards), available
-only in [different tiers of GitLab Enterprise Edition](#gitlab-enterprise-features-for-issue-boards),
+With [Multiple Issue Boards](#use-cases-for-multiple-issue-boards),
you go even further, as you can not only keep yourself and your project
organized from a broader perspective with one Issue Board per project,
but also allow your team members to organize their own workflow by creating
@@ -88,7 +84,7 @@ If we have the labels "**backend**", "**frontend**", "**staging**", and
"**production**", and an Issue Board with a list for each, we can:
- Visualize the entire flow of implementations since the
- beginning of the development lifecycle until deployed to production
+ beginning of the development life cycle until deployed to production
- Prioritize the issues in a list by moving them vertically
- Move issues between lists to organize them according to the labels you've set
- Add multiple issues to lists in the board by selecting one or more existing issues
@@ -97,8 +93,7 @@ If we have the labels "**backend**", "**frontend**", "**staging**", and
### Use cases for Multiple Issue Boards
-With [Multiple Issue Boards](#multiple-issue-boards-starter), available only in
-[GitLab Enterprise Edition](https://about.gitlab.com/pricing/),
+With [Multiple Issue Boards](#multiple-issue-boards),
each team can have their own board to organize their workflow individually.
#### Scrum team
@@ -159,13 +154,14 @@ Issue Board, that is, create or delete lists and drag issues from one list to an
GitLab Issue Boards are available on GitLab Core and GitLab.com Free, but some
advanced functionalities are only present in higher tiers: GitLab.com Bronze,
Silver, or Gold, or GitLab self-managed Starter, Premium, and Ultimate, as described
-on the following sections.
+in the following sections.
For a collection of [features per tier](#summary-of-features-per-tier), check the summary below.
-### Multiple Issue Boards **(STARTER)**
+### Multiple Issue Boards
-> Introduced in [GitLab Enterprise Edition 8.13](https://about.gitlab.com/2016/10/22/gitlab-8-13-released/#multiple-issue-boards-ee).
+> - Multiple Issue Boards per project [moved](https://gitlab.com/gitlab-org/gitlab-ce/issues/53811) to [GitLab Core](https://about.gitlab.com/pricing/) in GitLab 12.1.
+> - Multiple Issue Boards per group is available in [GitLab Premium Edition](https://about.gitlab.com/pricing/).
Multiple Issue Boards, as the name suggests, allow for more than one Issue Board
for a given project or group. This is great for large projects with more than one team
@@ -184,10 +180,6 @@ These are shortcuts to your last 4 visited boards.
When you're revisiting an issue board in a project or group with multiple boards,
GitLab will automatically load the last board you visited.
-NOTE: **Note:**
-The Multiple Issue Boards feature is available for
-**projects in GitLab Starter Edition** and for **groups in GitLab Premium Edition**.
-
### Configurable Issue Boards **(STARTER)**
> Introduced in [GitLab Starter Edition 10.2](https://about.gitlab.com/2017/11/22/gitlab-10-2-released/#issue-boards-configuration).
diff --git a/doc/workflow/forking/branch_select.png b/doc/workflow/forking/branch_select.png
index 77236137190..0ea5410f832 100644
--- a/doc/workflow/forking/branch_select.png
+++ b/doc/workflow/forking/branch_select.png
Binary files differ
diff --git a/doc/workflow/forking/merge_request.png b/doc/workflow/forking/merge_request.png
index 407ddfb4799..43851203f3f 100644
--- a/doc/workflow/forking/merge_request.png
+++ b/doc/workflow/forking/merge_request.png
Binary files differ
diff --git a/doc/workflow/forking_workflow.md b/doc/workflow/forking_workflow.md
index 869a0a621c3..82c2709143d 100644
--- a/doc/workflow/forking_workflow.md
+++ b/doc/workflow/forking_workflow.md
@@ -10,8 +10,7 @@ document more information about using branches to work together.
Forking a project is in most cases a two-step process.
-1. Click on the fork button located in the middle of the page or a project's
- home page right next to the stars button.
+1. Click on the fork button located located in between the star and clone buttons on the project's home page.
![Fork button](img/forking_workflow_fork_button.png)
@@ -25,7 +24,7 @@ Forking a project is in most cases a two-step process.
**Note:**
If the namespace you chose to fork the project to has another project with
the same path name, you will be presented with a warning that the forking
- could not be completed. Try to resolve the error and repeat the forking
+ could not be completed. Try to resolve the error before repeating the forking
process.
![Path taken error](img/forking_workflow_path_taken_error.png)
@@ -44,7 +43,7 @@ create the [merge request](merge_requests.md).
![Selecting branches](forking/branch_select.png)
You can then assign the merge request to someone to have them review
-your changes. Upon pressing the 'Accept Merge Request' button, your
+your changes. Upon pressing the 'Submit Merge Request' button, your
changes will be added to the repository and branch you're merging into.
![New merge request](forking/merge_request.png)
diff --git a/doc/workflow/img/forking_workflow_choose_namespace.png b/doc/workflow/img/forking_workflow_choose_namespace.png
index b34b12090a1..eb023ca85f2 100644
--- a/doc/workflow/img/forking_workflow_choose_namespace.png
+++ b/doc/workflow/img/forking_workflow_choose_namespace.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_fork_button.png b/doc/workflow/img/forking_workflow_fork_button.png
index 941d5363c35..7fb07529b6d 100644
--- a/doc/workflow/img/forking_workflow_fork_button.png
+++ b/doc/workflow/img/forking_workflow_fork_button.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_path_taken_error.png b/doc/workflow/img/forking_workflow_path_taken_error.png
index df938da5677..ef62d0ab6a9 100644
--- a/doc/workflow/img/forking_workflow_path_taken_error.png
+++ b/doc/workflow/img/forking_workflow_path_taken_error.png
Binary files differ
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index e16eeef202c..215178478d0 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -163,7 +163,8 @@ module API
with_labels_details: declared_params[:with_labels_details],
current_user: current_user,
project: user_project,
- issuable_metadata: issuable_meta_data(issues, 'Issue', current_user)
+ issuable_metadata: issuable_meta_data(issues, 'Issue', current_user),
+ include_subscribed: false
}
present issues, options
diff --git a/lib/api/pipelines.rb b/lib/api/pipelines.rb
index 667bf1ec801..9e888368e7b 100644
--- a/lib/api/pipelines.rb
+++ b/lib/api/pipelines.rb
@@ -4,7 +4,7 @@ module API
class Pipelines < Grape::API
include PaginationParams
- before { authenticate! }
+ before { authenticate_non_get! }
params do
requires :id, type: String, desc: 'The project ID'
@@ -32,6 +32,7 @@ module API
end
get ':id/pipelines' do
authorize! :read_pipeline, user_project
+ authorize! :read_build, user_project
pipelines = PipelinesFinder.new(user_project, current_user, params).execute
present paginate(pipelines), with: Entities::PipelineBasic
diff --git a/lib/feature/gitaly.rb b/lib/feature/gitaly.rb
index be397a478cd..656becbffd3 100644
--- a/lib/feature/gitaly.rb
+++ b/lib/feature/gitaly.rb
@@ -10,6 +10,7 @@ class Feature
get_commit_signatures
cache_invalidator
inforef_uploadpack_cache
+ get_all_lfs_pointers_go
].freeze
DEFAULT_ON_FLAGS = Set.new([]).freeze
diff --git a/lib/gitlab/analytics/cycle_analytics/default_stages.rb b/lib/gitlab/analytics/cycle_analytics/default_stages.rb
new file mode 100644
index 00000000000..286c393005f
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/default_stages.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+# This module represents the default Cycle Analytics stages that are currently provided by CE
+# Each method returns a hash that can be used to build a new stage object.
+#
+# Example:
+#
+# params = Gitlab::Analytics::CycleAnalytics::DefaultStages.params_for_issue_stage
+# Analytics::CycleAnalytics::ProjectStage.new(params)
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module DefaultStages
+ def self.all
+ [
+ params_for_issue_stage,
+ params_for_plan_stage,
+ params_for_code_stage,
+ params_for_test_stage,
+ params_for_review_stage,
+ params_for_staging_stage,
+ params_for_production_stage
+ ]
+ end
+
+ def self.params_for_issue_stage
+ {
+ name: 'issue',
+ custom: false, # this stage won't be customizable, we provide it as it is
+ relative_position: 1, # when opening the CycleAnalytics page in CE, this stage will be the first item
+ start_event_identifier: :issue_created, # IssueCreated class is used as start event
+ end_event_identifier: :issue_stage_end # IssueStageEnd class is used as end event
+ }
+ end
+
+ def self.params_for_plan_stage
+ {
+ name: 'plan',
+ custom: false,
+ relative_position: 2,
+ start_event_identifier: :plan_stage_start,
+ end_event_identifier: :issue_first_mentioned_in_commit
+ }
+ end
+
+ def self.params_for_code_stage
+ {
+ name: 'code',
+ custom: false,
+ relative_position: 3,
+ start_event_identifier: :code_stage_start,
+ end_event_identifier: :merge_request_created
+ }
+ end
+
+ def self.params_for_test_stage
+ {
+ name: 'test',
+ custom: false,
+ relative_position: 4,
+ start_event_identifier: :merge_request_last_build_started,
+ end_event_identifier: :merge_request_last_build_finished
+ }
+ end
+
+ def self.params_for_review_stage
+ {
+ name: 'review',
+ custom: false,
+ relative_position: 5,
+ start_event_identifier: :merge_request_created,
+ end_event_identifier: :merge_request_merged
+ }
+ end
+
+ def self.params_for_staging_stage
+ {
+ name: 'staging',
+ custom: false,
+ relative_position: 6,
+ start_event_identifier: :merge_request_merged,
+ end_event_identifier: :merge_request_first_deployed_to_production
+ }
+ end
+
+ def self.params_for_production_stage
+ {
+ name: 'production',
+ custom: false,
+ relative_position: 7,
+ start_event_identifier: :merge_request_merged,
+ end_event_identifier: :merge_request_first_deployed_to_production
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events.rb b/lib/gitlab/analytics/cycle_analytics/stage_events.rb
new file mode 100644
index 00000000000..d21f344f483
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ # Convention:
+ # Issue: < 100
+ # MergeRequest: >= 100 && < 1000
+ # Custom events for default stages: >= 1000 (legacy)
+ ENUM_MAPPING = {
+ StageEvents::IssueCreated => 1,
+ StageEvents::IssueFirstMentionedInCommit => 2,
+ StageEvents::MergeRequestCreated => 100,
+ StageEvents::MergeRequestFirstDeployedToProduction => 101,
+ StageEvents::MergeRequestLastBuildFinished => 102,
+ StageEvents::MergeRequestLastBuildStarted => 103,
+ StageEvents::MergeRequestMerged => 104,
+ StageEvents::CodeStageStart => 1_000,
+ StageEvents::IssueStageEnd => 1_001,
+ StageEvents::PlanStageStart => 1_002
+ }.freeze
+
+ EVENTS = ENUM_MAPPING.keys.freeze
+
+ # Defines which start_event and end_event pairs are allowed
+ PAIRING_RULES = {
+ StageEvents::PlanStageStart => [
+ StageEvents::IssueFirstMentionedInCommit
+ ],
+ StageEvents::CodeStageStart => [
+ StageEvents::MergeRequestCreated
+ ],
+ StageEvents::IssueCreated => [
+ StageEvents::IssueStageEnd
+ ],
+ StageEvents::MergeRequestCreated => [
+ StageEvents::MergeRequestMerged
+ ],
+ StageEvents::MergeRequestLastBuildStarted => [
+ StageEvents::MergeRequestLastBuildFinished
+ ],
+ StageEvents::MergeRequestMerged => [
+ StageEvents::MergeRequestFirstDeployedToProduction
+ ]
+ }.freeze
+
+ def [](identifier)
+ events.find { |e| e.identifier.to_s.eql?(identifier.to_s) } || raise(KeyError)
+ end
+
+ # hash for defining ActiveRecord enum: identifier => number
+ def to_enum
+ ENUM_MAPPING.each_with_object({}) { |(k, v), hash| hash[k.identifier] = v }
+ end
+
+ # will be overridden in EE with custom events
+ def pairing_rules
+ PAIRING_RULES
+ end
+
+ # will be overridden in EE with custom events
+ def events
+ EVENTS
+ end
+
+ module_function :[], :to_enum, :pairing_rules, :events
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start.rb
new file mode 100644
index 00000000000..ff9c8a79225
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class CodeStageStart < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Issue first mentioned in a commit")
+ end
+
+ def self.identifier
+ :code_stage_start
+ end
+
+ def object_type
+ MergeRequest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created.rb
new file mode 100644
index 00000000000..a601c9797f8
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class IssueCreated < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Issue created")
+ end
+
+ def self.identifier
+ :issue_created
+ end
+
+ def object_type
+ Issue
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit.rb
new file mode 100644
index 00000000000..7424043ef7b
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class IssueFirstMentionedInCommit < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Issue first mentioned in a commit")
+ end
+
+ def self.identifier
+ :issue_first_mentioned_in_commit
+ end
+
+ def object_type
+ Issue
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end.rb
new file mode 100644
index 00000000000..ceb229c552f
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class IssueStageEnd < SimpleStageEvent
+ def self.name
+ PlanStageStart.name
+ end
+
+ def self.identifier
+ :issue_stage_end
+ end
+
+ def object_type
+ Issue
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created.rb
new file mode 100644
index 00000000000..8be00831b4f
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class MergeRequestCreated < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Merge request created")
+ end
+
+ def self.identifier
+ :merge_request_created
+ end
+
+ def object_type
+ MergeRequest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production.rb
new file mode 100644
index 00000000000..6d7a2c023ff
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class MergeRequestFirstDeployedToProduction < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Merge request first deployed to production")
+ end
+
+ def self.identifier
+ :merge_request_first_deployed_to_production
+ end
+
+ def object_type
+ MergeRequest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished.rb
new file mode 100644
index 00000000000..12d82fe2c62
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class MergeRequestLastBuildFinished < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Merge request last build finish time")
+ end
+
+ def self.identifier
+ :merge_request_last_build_finished
+ end
+
+ def object_type
+ MergeRequest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started.rb
new file mode 100644
index 00000000000..9e749b0fdfa
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class MergeRequestLastBuildStarted < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Merge request last build start time")
+ end
+
+ def self.identifier
+ :merge_request_last_build_started
+ end
+
+ def object_type
+ MergeRequest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged.rb
new file mode 100644
index 00000000000..bbfb5d12992
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class MergeRequestMerged < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Merge request merged")
+ end
+
+ def self.identifier
+ :merge_request_merged
+ end
+
+ def object_type
+ MergeRequest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb
new file mode 100644
index 00000000000..803317d8b55
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ class PlanStageStart < SimpleStageEvent
+ def self.name
+ s_("CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board")
+ end
+
+ def self.identifier
+ :plan_stage_start
+ end
+
+ def object_type
+ Issue
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/simple_stage_event.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/simple_stage_event.rb
new file mode 100644
index 00000000000..253c489d822
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/simple_stage_event.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ # Represents a simple event that usually refers to one database column and does not require additional user input
+ class SimpleStageEvent < StageEvent
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb
new file mode 100644
index 00000000000..a55eee048c2
--- /dev/null
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Analytics
+ module CycleAnalytics
+ module StageEvents
+ # Base class for expressing an event that can be used for a stage.
+ class StageEvent
+ def initialize(params)
+ @params = params
+ end
+
+ def self.name
+ raise NotImplementedError
+ end
+
+ def self.identifier
+ raise NotImplementedError
+ end
+
+ def object_type
+ raise NotImplementedError
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index e17a096ef19..6769bd95c2b 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -198,12 +198,10 @@ module Gitlab
end.uniq
end
- # rubocop: disable CodeReuse/ActiveRecord
def deploy_token_check(login, password)
return unless password.present?
- token =
- DeployToken.active.find_by(token: password)
+ token = DeployToken.active.find_by_token(password)
return unless token && login
return if login != token.username
@@ -214,7 +212,6 @@ module Gitlab
Gitlab::Auth::Result.new(token, token.project, :deploy_token, scopes)
end
end
- # rubocop: enable CodeReuse/ActiveRecord
def lfs_token_check(login, encoded_token, project)
deploy_key_matches = login.match(/\Alfs\+deploy-key-(\d+)\z/)
diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb
index 09d1d79fefc..f121dce4cbb 100644
--- a/lib/gitlab/auth/o_auth/user.rb
+++ b/lib/gitlab/auth/o_auth/user.rb
@@ -77,7 +77,12 @@ module Gitlab
end
def bypass_two_factor?
- false
+ providers = Gitlab.config.omniauth.allow_bypass_two_factor
+ if providers.is_a?(Array)
+ providers.include?(auth_hash.provider)
+ else
+ providers
+ end
end
protected
diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb
index 332ca8bf9b8..5424298723e 100644
--- a/lib/gitlab/danger/helper.rb
+++ b/lib/gitlab/danger/helper.rb
@@ -126,6 +126,7 @@ module Gitlab
%r{\A(ee/)?vendor/(languages\.yml|licenses\.csv)\z} => :backend,
%r{\A(Dangerfile|Gemfile|Gemfile.lock|Procfile|Rakefile|\.gitlab-ci\.yml)\z} => :backend,
%r{\A[A-Z_]+_VERSION\z} => :backend,
+ %r{\A\.rubocop(_todo)?\.yml\z} => :backend,
%r{\A(ee/)?qa/} => :qa,
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index cbdff0ab060..a12bbededc4 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -195,13 +195,14 @@ module Gitlab
# pool_size - The size of the DB pool.
# host - An optional host name to use instead of the default one.
- def self.create_connection_pool(pool_size, host = nil)
+ def self.create_connection_pool(pool_size, host = nil, port = nil)
# See activerecord-4.2.7.1/lib/active_record/connection_adapters/connection_specification.rb
env = Rails.env
original_config = ActiveRecord::Base.configurations
env_config = original_config[env].merge('pool' => pool_size)
env_config['host'] = host if host
+ env_config['port'] = port if port
config = original_config.merge(env => env_config)
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 9bba4f6ce1e..57a413f8e04 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -470,7 +470,7 @@ module Gitlab
# We set the default value _after_ adding the column so we don't end up
# updating any existing data with the default value. This isn't
# necessary since we copy over old values further down.
- change_column_default(table, new, old_col.default) if old_col.default
+ change_column_default(table, new, old_col.default) unless old_col.default.nil?
install_rename_triggers(table, old, new)
@@ -482,6 +482,16 @@ module Gitlab
copy_foreign_keys(table, old, new)
end
+ def undo_rename_column_concurrently(table, old, new)
+ trigger_name = rename_trigger_name(table, old, new)
+
+ check_trigger_permissions!(table)
+
+ remove_rename_triggers_for_postgresql(table, trigger_name)
+
+ remove_column(table, new)
+ end
+
# Installs triggers in a table that keep a new column in sync with an old
# one.
#
@@ -547,6 +557,35 @@ module Gitlab
remove_column(table, old)
end
+ def undo_cleanup_concurrent_column_rename(table, old, new, type: nil)
+ if transaction_open?
+ raise 'undo_cleanup_concurrent_column_rename can not be run inside a transaction'
+ end
+
+ check_trigger_permissions!(table)
+
+ new_column = column_for(table, new)
+
+ add_column(table, old, type || new_column.type,
+ limit: new_column.limit,
+ precision: new_column.precision,
+ scale: new_column.scale)
+
+ # We set the default value _after_ adding the column so we don't end up
+ # updating any existing data with the default value. This isn't
+ # necessary since we copy over old values further down.
+ change_column_default(table, old, new_column.default) unless new_column.default.nil?
+
+ install_rename_triggers(table, old, new)
+
+ update_column_in_batches(table, old, Arel::Table.new(table)[new])
+
+ change_column_null(table, old, false) unless new_column.null
+
+ copy_indexes(table, new, old)
+ copy_foreign_keys(table, new, old)
+ end
+
# Changes the column type of a table using a background migration.
#
# Because this method uses a background migration it's more suitable for
@@ -747,6 +786,11 @@ module Gitlab
EOF
execute <<-EOF.strip_heredoc
+ DROP TRIGGER IF EXISTS #{trigger}
+ ON #{table}
+ EOF
+
+ execute <<-EOF.strip_heredoc
CREATE TRIGGER #{trigger}
BEFORE INSERT OR UPDATE
ON #{table}
diff --git a/lib/gitlab/database_importers/self_monitoring/project/create_service.rb b/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
new file mode 100644
index 00000000000..9387a76369f
--- /dev/null
+++ b/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
@@ -0,0 +1,249 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module DatabaseImporters
+ module SelfMonitoring
+ module Project
+ class CreateService < ::BaseService
+ include Stepable
+
+ STEPS_ALLOWED_TO_FAIL = [
+ :validate_application_settings, :validate_project_created, :validate_admins
+ ].freeze
+
+ VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
+ PROJECT_NAME = 'GitLab Instance Administration'
+
+ steps :validate_application_settings,
+ :validate_project_created,
+ :validate_admins,
+ :create_group,
+ :create_project,
+ :save_project_id,
+ :add_group_members,
+ :add_to_whitelist,
+ :add_prometheus_manual_configuration
+
+ def initialize
+ super(nil)
+ end
+
+ def execute!
+ result = execute_steps
+
+ if result[:status] == :success
+ result
+ elsif STEPS_ALLOWED_TO_FAIL.include?(result[:failed_step])
+ success
+ else
+ raise StandardError, result[:message]
+ end
+ end
+
+ private
+
+ def validate_application_settings
+ return success if application_settings
+
+ log_error(_('No application_settings found'))
+ error(_('No application_settings found'))
+ end
+
+ def validate_project_created
+ return success unless project_created?
+
+ log_error(_('Project already created'))
+ error(_('Project already created'))
+ end
+
+ def validate_admins
+ unless instance_admins.any?
+ log_error(_('No active admin user found'))
+ return error(_('No active admin user found'))
+ end
+
+ success
+ end
+
+ def create_group
+ if project_created?
+ log_info(_('Instance administrators group already exists'))
+ @group = application_settings.instance_administration_project.owner
+ return success(group: @group)
+ end
+
+ @group = ::Groups::CreateService.new(group_owner, create_group_params).execute
+
+ if @group.persisted?
+ success(group: @group)
+ else
+ error(_('Could not create group'))
+ end
+ end
+
+ def create_project
+ if project_created?
+ log_info(_('Instance administration project already exists'))
+ @project = application_settings.instance_administration_project
+ return success(project: project)
+ end
+
+ @project = ::Projects::CreateService.new(group_owner, create_project_params).execute
+
+ if project.persisted?
+ success(project: project)
+ else
+ log_error(_("Could not create instance administration project. Errors: %{errors}") % { errors: project.errors.full_messages })
+ error(_('Could not create project'))
+ end
+ end
+
+ def save_project_id
+ return success if project_created?
+
+ result = application_settings.update(instance_administration_project_id: @project.id)
+
+ if result
+ success
+ else
+ log_error(_("Could not save instance administration project ID, errors: %{errors}") % { errors: application_settings.errors.full_messages })
+ error(_('Could not save project ID'))
+ end
+ end
+
+ def add_group_members
+ members = @group.add_users(members_to_add, Gitlab::Access::MAINTAINER)
+ errors = members.flat_map { |member| member.errors.full_messages }
+
+ if errors.any?
+ log_error(_('Could not add admins as members to self-monitoring project. Errors: %{errors}') % { errors: errors })
+ error(_('Could not add admins as members'))
+ else
+ success
+ end
+ end
+
+ def add_to_whitelist
+ return success unless prometheus_enabled?
+ return success unless prometheus_listen_address.present?
+
+ uri = parse_url(internal_prometheus_listen_address_uri)
+ return error(_('Prometheus listen_address is not a valid URI')) unless uri
+
+ application_settings.add_to_outbound_local_requests_whitelist([uri.normalized_host])
+ result = application_settings.save
+
+ if result
+ # Expire the Gitlab::CurrentSettings cache after updating the whitelist.
+ # This happens automatically in an after_commit hook, but in migrations,
+ # the after_commit hook only runs at the end of the migration.
+ Gitlab::CurrentSettings.expire_current_application_settings
+ success
+ else
+ log_error(_("Could not add prometheus URL to whitelist, errors: %{errors}") % { errors: application_settings.errors.full_messages })
+ error(_('Could not add prometheus URL to whitelist'))
+ end
+ end
+
+ def add_prometheus_manual_configuration
+ return success unless prometheus_enabled?
+ return success unless prometheus_listen_address.present?
+
+ service = project.find_or_initialize_service('prometheus')
+
+ unless service.update(prometheus_service_attributes)
+ log_error(_('Could not save prometheus manual configuration for self-monitoring project. Errors: %{errors}') % { errors: service.errors.full_messages })
+ return error(_('Could not save prometheus manual configuration'))
+ end
+
+ success
+ end
+
+ def application_settings
+ @application_settings ||= ApplicationSetting.current_without_cache
+ end
+
+ def project_created?
+ application_settings.instance_administration_project.present?
+ end
+
+ def parse_url(uri_string)
+ Addressable::URI.parse(uri_string)
+ rescue Addressable::URI::InvalidURIError, TypeError
+ end
+
+ def prometheus_enabled?
+ Gitlab.config.prometheus.enable
+ rescue Settingslogic::MissingSetting
+ log_error(_('prometheus.enable is not present in gitlab.yml'))
+
+ false
+ end
+
+ def prometheus_listen_address
+ Gitlab.config.prometheus.listen_address
+ rescue Settingslogic::MissingSetting
+ log_error(_('prometheus.listen_address is not present in gitlab.yml'))
+
+ nil
+ end
+
+ def instance_admins
+ @instance_admins ||= User.admins.active
+ end
+
+ def group_owner
+ instance_admins.first
+ end
+
+ def members_to_add
+ # Exclude admins who are already members of group because
+ # `@group.add_users(users)` returns an error if the users parameter contains
+ # users who are already members of the group.
+ instance_admins - @group.members.collect(&:user)
+ end
+
+ def create_group_params
+ {
+ name: 'GitLab Instance Administrators',
+ path: "gitlab-instance-administrators-#{SecureRandom.hex(4)}",
+ visibility_level: VISIBILITY_LEVEL
+ }
+ end
+
+ def docs_path
+ Rails.application.routes.url_helpers.help_page_path(
+ 'administration/monitoring/gitlab_instance_administration_project/index'
+ )
+ end
+
+ def create_project_params
+ {
+ initialize_with_readme: true,
+ visibility_level: VISIBILITY_LEVEL,
+ name: PROJECT_NAME,
+ description: "This project is automatically generated and will be used to help monitor this GitLab instance. [More information](#{docs_path})",
+ namespace_id: @group.id
+ }
+ end
+
+ def internal_prometheus_listen_address_uri
+ if prometheus_listen_address.starts_with?('http')
+ prometheus_listen_address
+ else
+ 'http://' + prometheus_listen_address
+ end
+ end
+
+ def prometheus_service_attributes
+ {
+ api_url: internal_prometheus_listen_address_uri,
+ manual_configuration: true,
+ active: true
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb
index 3c71031a8d9..841f9de8d4a 100644
--- a/lib/gitlab/fogbugz_import/project_creator.rb
+++ b/lib/gitlab/fogbugz_import/project_creator.rb
@@ -20,7 +20,7 @@ module Gitlab
path: repo.path,
namespace: namespace,
creator: current_user,
- visibility_level: Gitlab::VisibilityLevel::INTERNAL,
+ visibility_level: Gitlab::VisibilityLevel::PRIVATE,
import_type: 'fogbugz',
import_source: repo.name,
import_url: Project::UNKNOWN_IMPORT_URL,
diff --git a/lib/gitlab/graphql/present/instrumentation.rb b/lib/gitlab/graphql/present/instrumentation.rb
index ab03c40c22d..941a4f434a1 100644
--- a/lib/gitlab/graphql/present/instrumentation.rb
+++ b/lib/gitlab/graphql/present/instrumentation.rb
@@ -23,7 +23,9 @@ module Gitlab
end
presenter = presented_in.presenter_class.new(object, **context.to_h)
- wrapped = presented_type.class.new(presenter, context)
+
+ # we have to use the new `authorized_new` method, as `new` is protected
+ wrapped = presented_type.class.authorized_new(presenter, context)
old_resolver.call(wrapped, args, context)
end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 353298e67b3..a93301cb4ce 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -142,7 +142,8 @@ module Gitlab
Gitlab::UsageDataCounters::SnippetCounter,
Gitlab::UsageDataCounters::SearchCounter,
Gitlab::UsageDataCounters::CycleAnalyticsCounter,
- Gitlab::UsageDataCounters::SourceCodeCounter
+ Gitlab::UsageDataCounters::SourceCodeCounter,
+ Gitlab::UsageDataCounters::MergeRequestCounter
]
end
diff --git a/lib/gitlab/usage_data_counters/merge_request_counter.rb b/lib/gitlab/usage_data_counters/merge_request_counter.rb
new file mode 100644
index 00000000000..e786e595f77
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/merge_request_counter.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module UsageDataCounters
+ class MergeRequestCounter < BaseCounter
+ KNOWN_EVENTS = %w[create].freeze
+ PREFIX = 'merge_request'
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index a07ae3a418a..7a42e4e92a0 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -10,15 +10,9 @@ namespace :gitlab do
rake:assets:precompile
webpack:compile
gitlab:assets:fix_urls
- gitlab:assets:compile_vrt
].each(&Gitlab::TaskHelpers.method(:invoke_and_time_task))
end
- desc 'GitLab | Assets | Compile visual review toolbar'
- task :compile_vrt do
- system 'yarn', 'webpack-vrt'
- end
-
desc 'GitLab | Assets | Clean up old compiled frontend assets'
task clean: ['rake:assets:clean']
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 4f3c8e8046d..e44c18979cd 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2977,6 +2977,9 @@ msgstr ""
msgid "Commands applied"
msgstr ""
+msgid "Commands did not apply"
+msgstr ""
+
msgid "Comment"
msgstr ""
@@ -3353,6 +3356,12 @@ msgstr ""
msgid "Copy token to clipboard"
msgstr ""
+msgid "Could not add admins as members"
+msgstr ""
+
+msgid "Could not add admins as members to self-monitoring project. Errors: %{errors}"
+msgstr ""
+
msgid "Could not add prometheus URL to whitelist"
msgstr ""
@@ -3371,6 +3380,9 @@ msgstr ""
msgid "Could not create Wiki Repository at this time. Please try again later."
msgstr ""
+msgid "Could not create group"
+msgstr ""
+
msgid "Could not create instance administration project. Errors: %{errors}"
msgstr ""
@@ -3398,6 +3410,12 @@ msgstr ""
msgid "Could not save project ID"
msgstr ""
+msgid "Could not save prometheus manual configuration"
+msgstr ""
+
+msgid "Could not save prometheus manual configuration for self-monitoring project. Errors: %{errors}"
+msgstr ""
+
msgid "Coverage"
msgstr ""
@@ -3602,6 +3620,30 @@ msgstr ""
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
+msgid "CycleAnalyticsEvent|Issue created"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request created"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request first deployed to production"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request last build finish time"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request last build start time"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request merged"
+msgstr ""
+
msgid "CycleAnalyticsStage|Code"
msgstr ""
@@ -7071,9 +7113,6 @@ msgstr ""
msgid "Minimum length is %{minimum_password_length} characters."
msgstr ""
-msgid "Mirror a repository"
-msgstr ""
-
msgid "Mirror direction"
msgstr ""
@@ -7376,9 +7415,15 @@ msgstr ""
msgid "No Tag"
msgstr ""
+msgid "No active admin user found"
+msgstr ""
+
msgid "No activities found"
msgstr ""
+msgid "No application_settings found"
+msgstr ""
+
msgid "No available namespaces to fork the project."
msgstr ""
@@ -8002,7 +8047,7 @@ msgstr ""
msgid "PipelineSheduleIntervalPattern|Custom"
msgstr ""
-msgid "PipelineStatusTooltip|Commit: %{ci_status}"
+msgid "PipelineStatusTooltip|Pipeline: %{ciStatus}"
msgstr ""
msgid "PipelineStatusTooltip|Pipeline: %{ci_status}"
@@ -8254,7 +8299,7 @@ msgstr ""
msgid "Preferences|Behavior"
msgstr ""
-msgid "Preferences|Choose between fixed (max. 1280px) and fluid (100%%) application layout."
+msgid "Preferences|Choose between fixed (max. 1280px) and fluid (%{percentage}) application layout."
msgstr ""
msgid "Preferences|Choose what content you want to see on a project’s overview page."
@@ -8722,6 +8767,9 @@ msgstr ""
msgid "Project access must be granted explicitly to each user."
msgstr ""
+msgid "Project already created"
+msgstr ""
+
msgid "Project and wiki repositories"
msgstr ""
@@ -13919,6 +13967,9 @@ msgstr ""
msgid "pending comment"
msgstr ""
+msgid "pipeline"
+msgstr ""
+
msgid "private"
msgstr ""
@@ -13934,6 +13985,12 @@ msgstr ""
msgid "project avatar"
msgstr ""
+msgid "prometheus.enable is not present in gitlab.yml"
+msgstr ""
+
+msgid "prometheus.listen_address is not present in gitlab.yml"
+msgstr ""
+
msgid "quick actions"
msgstr ""
diff --git a/package.json b/package.json
index df5f758fa20..8fa34cdea28 100644
--- a/package.json
+++ b/package.json
@@ -26,8 +26,7 @@
"stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint-utility-map.js",
"test": "node scripts/frontend/test",
"webpack": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.config.js",
- "webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.js",
- "webpack-vrt": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.review_toolbar.js"
+ "webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.js"
},
"dependencies": {
"@babel/core": "^7.5.5",
@@ -38,8 +37,9 @@
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.5.5",
"@gitlab/csslab": "^1.9.0",
- "@gitlab/svgs": "^1.68.0",
- "@gitlab/ui": "5.18.0",
+ "@gitlab/svgs": "^1.70.0",
+ "@gitlab/ui": "5.19.0",
+ "@gitlab/visual-review-tools": "^1.0.0",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
diff --git a/qa/Dockerfile b/qa/Dockerfile
index 3309f5b6ce3..84dbfae1008 100644
--- a/qa/Dockerfile
+++ b/qa/Dockerfile
@@ -50,6 +50,8 @@ RUN export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
WORKDIR /home/gitlab/qa
COPY ./qa/Gemfile* /home/gitlab/qa/
COPY ./config/initializers/0_inject_enterprise_edition_module.rb /home/gitlab/config/initializers/
+# Copy VERSION to ensure the COPY succeeds to copy at least one file since ee/app/models/license.rb isn't present in CE
+COPY VERSION ./ee/app/models/license.r[b] /home/gitlab/ee/app/models/
COPY ./lib/gitlab.rb /home/gitlab/lib/
COPY ./INSTALLATION_TYPE /home/gitlab/
COPY ./VERSION /home/gitlab/
diff --git a/qa/qa.rb b/qa/qa.rb
index 8be2a289422..a760f72f70d 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -359,6 +359,13 @@ module QA
autoload :KubernetesCluster, 'qa/service/kubernetes_cluster'
autoload :Omnibus, 'qa/service/omnibus'
autoload :Runner, 'qa/service/runner'
+
+ module ClusterProvider
+ autoload :Base, 'qa/service/cluster_provider/base'
+ autoload :Gcloud, 'qa/service/cluster_provider/gcloud'
+ autoload :Minikube, 'qa/service/cluster_provider/minikube'
+ autoload :K3d, 'qa/service/cluster_provider/k3d'
+ end
end
##
diff --git a/qa/qa/service/cluster_provider/base.rb b/qa/qa/service/cluster_provider/base.rb
new file mode 100644
index 00000000000..a9678557aca
--- /dev/null
+++ b/qa/qa/service/cluster_provider/base.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class Base
+ include Service::Shellout
+
+ attr_reader :rbac
+
+ def initialize(rbac:)
+ @rbac = rbac
+ end
+
+ def cluster_name
+ @cluster_name ||= "qa-cluster-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}-#{SecureRandom.hex(4)}"
+ end
+
+ def set_credentials(admin_user)
+ raise NotImplementedError
+ end
+
+ def validate_dependencies
+ raise NotImplementedError
+ end
+
+ def setup
+ raise NotImplementedError
+ end
+
+ def teardown
+ raise NotImplementedError
+ end
+
+ def filter_credentials(credentials)
+ credentials
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/cluster_provider/gcloud.rb b/qa/qa/service/cluster_provider/gcloud.rb
new file mode 100644
index 00000000000..9c82151666c
--- /dev/null
+++ b/qa/qa/service/cluster_provider/gcloud.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class Gcloud < Base
+ def validate_dependencies
+ find_executable('gcloud') || raise("You must first install `gcloud` executable to run these tests.")
+ end
+
+ def set_credentials(admin_user)
+ master_auth = JSON.parse(`gcloud container clusters describe #{cluster_name} --region #{Runtime::Env.gcloud_region} --format 'json(masterAuth.username, masterAuth.password)'`)
+
+ shell <<~CMD.tr("\n", ' ')
+ kubectl config set-credentials #{admin_user}
+ --username #{master_auth['masterAuth']['username']}
+ --password #{master_auth['masterAuth']['password']}
+ CMD
+ end
+
+ def setup
+ login_if_not_already_logged_in
+ create_cluster
+ end
+
+ def teardown
+ delete_cluster
+ end
+
+ private
+
+ def login_if_not_already_logged_in
+ if Runtime::Env.has_gcloud_credentials?
+ attempt_login_with_env_vars
+ else
+ account = `gcloud auth list --filter=status:ACTIVE --format="value(account)"`
+ if account.empty?
+ raise "Failed to login to gcloud. No credentials provided in environment and no credentials found locally."
+ else
+ puts "gcloud account found. Using: #{account} for creating K8s cluster."
+ end
+ end
+ end
+
+ def attempt_login_with_env_vars
+ puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY."
+ gcloud_account_key = Tempfile.new('gcloud-account-key')
+ gcloud_account_key.write(Runtime::Env.gcloud_account_key)
+ gcloud_account_key.close
+ gcloud_account_email = Runtime::Env.gcloud_account_email
+ shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}")
+ ensure
+ gcloud_account_key && gcloud_account_key.unlink
+ end
+
+ def auth_options
+ "--enable-legacy-authorization" unless rbac
+ end
+
+ def create_cluster
+ shell <<~CMD.tr("\n", ' ')
+ gcloud container clusters
+ create #{cluster_name}
+ #{auth_options}
+ --enable-basic-auth
+ --region #{Runtime::Env.gcloud_region}
+ --disk-size 10GB
+ --num-nodes #{Runtime::Env.gcloud_num_nodes}
+ && gcloud container clusters
+ get-credentials
+ --region #{Runtime::Env.gcloud_region}
+ #{cluster_name}
+ CMD
+ end
+
+ def delete_cluster
+ shell <<~CMD.tr("\n", ' ')
+ gcloud container clusters delete
+ --region #{Runtime::Env.gcloud_region}
+ #{cluster_name}
+ --quiet --async
+ CMD
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/cluster_provider/k3d.rb b/qa/qa/service/cluster_provider/k3d.rb
new file mode 100644
index 00000000000..8e117c2dbd5
--- /dev/null
+++ b/qa/qa/service/cluster_provider/k3d.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class K3d < Base
+ def validate_dependencies
+ find_executable('k3d') || raise("You must first install `k3d` executable to run these tests.")
+ end
+
+ def set_credentials(admin_user)
+ end
+
+ def setup
+ shell "k3d create --workers 1 --name #{cluster_name} --wait 0"
+
+ @old_kubeconfig = ENV['KUBECONFIG']
+ ENV['KUBECONFIG'] = fetch_kubeconfig
+ raise "Could not fetch kubeconfig" unless ENV['KUBECONFIG']
+
+ install_local_storage
+ end
+
+ def teardown
+ ENV['KUBECONFIG'] = @old_kubeconfig
+ shell "k3d delete --name #{cluster_name}"
+ end
+
+ # Fetch "real" certificate
+ # See https://github.com/rancher/k3s/issues/27
+ def filter_credentials(credentials)
+ kubeconfig = YAML.load_file(ENV['KUBECONFIG'])
+ ca_certificate = kubeconfig.dig('clusters', 0, 'cluster', 'certificate-authority-data')
+
+ credentials.merge('data' => credentials['data'].merge('ca.crt' => ca_certificate))
+ end
+
+ private
+
+ def retry_until(max_attempts: 10, wait: 1)
+ max_attempts.times do
+ result = yield
+ return result if result
+
+ sleep wait
+ end
+
+ raise "Retried #{max_attempts} times. Aborting"
+ end
+
+ def fetch_kubeconfig
+ retry_until do
+ config = `k3d get-kubeconfig --name #{cluster_name}`.chomp
+ config if config =~ /kubeconfig.yaml/
+ end
+ end
+
+ def install_local_storage
+ shell('kubectl apply -f -', stdin_data: local_storage_config)
+ end
+
+ # See https://github.com/rancher/k3d/issues/67
+ def local_storage_config
+ <<~YAML
+ ---
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: storage-provisioner
+ namespace: kube-system
+ ---
+ apiVersion: rbac.authorization.k8s.io/v1
+ kind: ClusterRoleBinding
+ metadata:
+ name: storage-provisioner
+ roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: system:persistent-volume-provisioner
+ subjects:
+ - kind: ServiceAccount
+ name: storage-provisioner
+ namespace: kube-system
+ ---
+ apiVersion: v1
+ kind: Pod
+ metadata:
+ name: storage-provisioner
+ namespace: kube-system
+ spec:
+ serviceAccountName: storage-provisioner
+ tolerations:
+ - effect: NoExecute
+ key: node.kubernetes.io/not-ready
+ operator: Exists
+ tolerationSeconds: 300
+ - effect: NoExecute
+ key: node.kubernetes.io/unreachable
+ operator: Exists
+ tolerationSeconds: 300
+ hostNetwork: true
+ containers:
+ - name: storage-provisioner
+ image: gcr.io/k8s-minikube/storage-provisioner:v1.8.1
+ command: ["/storage-provisioner"]
+ imagePullPolicy: IfNotPresent
+ volumeMounts:
+ - mountPath: /tmp
+ name: tmp
+ volumes:
+ - name: tmp
+ hostPath:
+ path: /tmp
+ type: Directory
+ ---
+ kind: StorageClass
+ apiVersion: storage.k8s.io/v1
+ metadata:
+ name: standard
+ namespace: kube-system
+ annotations:
+ storageclass.kubernetes.io/is-default-class: "true"
+ labels:
+ addonmanager.kubernetes.io/mode: EnsureExists
+ provisioner: k8s.io/minikube-hostpath
+ YAML
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/cluster_provider/minikube.rb b/qa/qa/service/cluster_provider/minikube.rb
new file mode 100644
index 00000000000..fc916245357
--- /dev/null
+++ b/qa/qa/service/cluster_provider/minikube.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class Minikube < Base
+ def validate_dependencies
+ find_executable('minikube') || raise("You must first install `minikube` executable to run these tests.")
+ end
+
+ def set_credentials(admin_user)
+ end
+
+ def setup
+ shell 'minikube stop'
+ shell "minikube profile #{cluster_name}"
+ shell 'minikube start'
+ end
+
+ def teardown
+ shell 'minikube delete'
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb
index ac0b6313167..26b5f58d2d3 100644
--- a/qa/qa/service/kubernetes_cluster.rb
+++ b/qa/qa/service/kubernetes_cluster.rb
@@ -9,90 +9,63 @@ module QA
class KubernetesCluster
include Service::Shellout
- attr_reader :api_url, :ca_certificate, :token, :rbac
+ attr_reader :api_url, :ca_certificate, :token, :rbac, :provider
- def initialize(rbac: true)
+ def initialize(rbac: true, provider_class: QA::Service::ClusterProvider::Gcloud)
@rbac = rbac
- end
-
- def cluster_name
- @cluster_name ||= "qa-cluster-#{SecureRandom.hex(4)}-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}"
+ @provider = provider_class.new(rbac: rbac)
end
def create!
validate_dependencies
- login_if_not_already_logged_in
-
- shell <<~CMD.tr("\n", ' ')
- gcloud container clusters
- create #{cluster_name}
- #{auth_options}
- --enable-basic-auth
- --region #{Runtime::Env.gcloud_region}
- --disk-size 10GB
- --num-nodes #{Runtime::Env.gcloud_num_nodes}
- && gcloud container clusters
- get-credentials
- --region #{Runtime::Env.gcloud_region}
- #{cluster_name}
- CMD
-
- @api_url = `kubectl config view --minify -o jsonpath='{.clusters[].cluster.server}'`
-
- @admin_user = "#{cluster_name}-admin"
- master_auth = JSON.parse(`gcloud container clusters describe #{cluster_name} --region #{Runtime::Env.gcloud_region} --format 'json(masterAuth.username, masterAuth.password)'`)
- shell <<~CMD.tr("\n", ' ')
- kubectl config set-credentials #{@admin_user}
- --username #{master_auth['masterAuth']['username']}
- --password #{master_auth['masterAuth']['password']}
- CMD
-
- if rbac
- create_service_account
-
- secrets = JSON.parse(`kubectl get secrets -o json`)
- gitlab_account = secrets['items'].find do |item|
- item['metadata']['annotations']['kubernetes.io/service-account.name'] == 'gitlab-account'
- end
-
- @ca_certificate = Base64.decode64(gitlab_account['data']['ca.crt'])
- @token = Base64.decode64(gitlab_account['data']['token'])
- else
- @ca_certificate = Base64.decode64(`kubectl get secrets -o jsonpath="{.items[0].data['ca\\.crt']}"`)
- @token = Base64.decode64(`kubectl get secrets -o jsonpath='{.items[0].data.token}'`)
- end
+
+ @provider.validate_dependencies
+ @provider.setup
+
+ @api_url = fetch_api_url
+
+ credentials = @provider.filter_credentials(fetch_credentials)
+ @ca_certificate = Base64.decode64(credentials.dig('data', 'ca.crt'))
+ @token = Base64.decode64(credentials.dig('data', 'token'))
self
end
def remove!
- shell <<~CMD.tr("\n", ' ')
- gcloud container clusters delete
- --region #{Runtime::Env.gcloud_region}
- #{cluster_name}
- --quiet --async
- CMD
+ @provider.teardown
+ end
+
+ def cluster_name
+ @provider.cluster_name
end
private
- def create_service_account
- shell('kubectl create -f -', stdin_data: service_account)
- shell("kubectl --user #{@admin_user} create -f -", stdin_data: service_account_role_binding)
+ def fetch_api_url
+ `kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'`
+ end
+
+ def fetch_credentials
+ return global_credentials unless rbac
+
+ @provider.set_credentials(admin_user)
+ create_service_account(admin_user)
+ account_credentials
end
- def service_account
- <<~YAML
+ def admin_user
+ @admin_user ||= "#{@provider.cluster_name}-admin"
+ end
+
+ def create_service_account(user)
+ service_account = <<~YAML
+ ---
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab-account
namespace: default
- YAML
- end
-
- def service_account_role_binding
- <<~YAML
+ ---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
@@ -106,39 +79,24 @@ module QA
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
YAML
- end
- def auth_options
- "--enable-legacy-authorization" unless rbac
+ shell('kubectl apply -f -', stdin_data: service_account)
end
- def validate_dependencies
- find_executable('gcloud') || raise("You must first install `gcloud` executable to run these tests.")
- find_executable('kubectl') || raise("You must first install `kubectl` executable to run these tests.")
- end
+ def account_credentials
+ secrets = JSON.parse(`kubectl get secrets -o json`)
- def login_if_not_already_logged_in
- if Runtime::Env.has_gcloud_credentials?
- attempt_login_with_env_vars
- else
- account = `gcloud auth list --filter=status:ACTIVE --format="value(account)"`
- if account.empty?
- raise "Failed to login to gcloud. No credentials provided in environment and no credentials found locally."
- else
- puts "gcloud account found. Using: #{account} for creating K8s cluster."
- end
+ secrets['items'].find do |item|
+ item['metadata']['annotations']['kubernetes.io/service-account.name'] == 'gitlab-account'
end
end
- def attempt_login_with_env_vars
- puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY."
- gcloud_account_key = Tempfile.new('gcloud-account-key')
- gcloud_account_key.write(Runtime::Env.gcloud_account_key)
- gcloud_account_key.close
- gcloud_account_email = Runtime::Env.gcloud_account_email
- shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}")
- ensure
- gcloud_account_key && gcloud_account_key.unlink
+ def global_credentials
+ JSON.parse(`kubectl get secrets -o jsonpath='{.items[0]}'`)
+ end
+
+ def validate_dependencies
+ find_executable('kubectl') || raise("You must first install `kubectl` executable to run these tests.")
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
index 458072b1507..567c6a83ddf 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/127
- context 'Create', :quarantine do
+ context 'Create' do
describe 'File templates' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
index 9ff7919f199..c09c65a57a5 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create', :quarantine do
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/127
+ context 'Create' do
describe 'Web IDE file templates' do
include Runtime::Fixtures
diff --git a/rubocop/cop/gitlab/httparty.rb b/rubocop/cop/gitlab/httparty.rb
index 215f18b6993..8acebff624d 100644
--- a/rubocop/cop/gitlab/httparty.rb
+++ b/rubocop/cop/gitlab/httparty.rb
@@ -1,11 +1,9 @@
-require_relative '../../spec_helpers'
+# frozen_string_literal: true
module RuboCop
module Cop
module Gitlab
class HTTParty < RuboCop::Cop::Cop
- include SpecHelpers
-
MSG_SEND = <<~EOL.freeze
Avoid calling `HTTParty` directly. Instead, use the Gitlab::HTTP
wrapper. To allow request to localhost or the private network set
@@ -27,8 +25,6 @@ module RuboCop
PATTERN
def on_send(node)
- return if in_spec?(node)
-
add_offense(node, location: :expression, message: MSG_SEND) if httparty_node?(node)
add_offense(node, location: :expression, message: MSG_INCLUDE) if includes_httparty?(node)
end
diff --git a/rubocop/cop/gitlab/union.rb b/rubocop/cop/gitlab/union.rb
index 09541d8af3b..c44c847657b 100644
--- a/rubocop/cop/gitlab/union.rb
+++ b/rubocop/cop/gitlab/union.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-require_relative '../../spec_helpers'
module RuboCop
module Cop
@@ -7,8 +6,6 @@ module RuboCop
# Cop that disallows the use of `Gitlab::SQL::Union`, in favour of using
# the `FromUnion` module.
class Union < RuboCop::Cop::Cop
- include SpecHelpers
-
MSG = 'Use the `FromUnion` concern, instead of using `Gitlab::SQL::Union` directly'
def_node_matcher :raw_union?, <<~PATTERN
@@ -17,7 +14,6 @@ module RuboCop
def on_send(node)
return unless raw_union?(node)
- return if in_spec?(node)
add_offense(node, location: :expression)
end
diff --git a/rubocop/cop/graphql/authorize_types.rb b/rubocop/cop/graphql/authorize_types.rb
index 93fe80c3edf..cd8bdbaee59 100644
--- a/rubocop/cop/graphql/authorize_types.rb
+++ b/rubocop/cop/graphql/authorize_types.rb
@@ -1,13 +1,9 @@
# frozen_string_literal: true
-require_relative '../../spec_helpers'
-
module RuboCop
module Cop
module Graphql
class AuthorizeTypes < RuboCop::Cop::Cop
- include SpecHelpers
-
MSG = 'Add an `authorize :ability` call to the type: '\
'https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#type-authorization'
@@ -32,8 +28,6 @@ module RuboCop
private
def in_type?(node)
- return if in_spec?(node)
-
path = node.location.expression.source_buffer.name
path.include?(TYPES_DIR)
diff --git a/rubocop/cop/include_action_view_context.rb b/rubocop/cop/include_action_view_context.rb
index 14662a33e95..52c84a711c9 100644
--- a/rubocop/cop/include_action_view_context.rb
+++ b/rubocop/cop/include_action_view_context.rb
@@ -1,13 +1,9 @@
# frozen_string_literal: true
-require_relative '../spec_helpers'
-
module RuboCop
module Cop
# Cop that makes sure workers include `::Gitlab::ActionViewOutput::Context`, not `ActionView::Context`.
class IncludeActionViewContext < RuboCop::Cop::Cop
- include SpecHelpers
-
MSG = 'Include `::Gitlab::ActionViewOutput::Context`, not `ActionView::Context`, for Rails 5.'.freeze
def_node_matcher :includes_action_view_context?, <<~PATTERN
@@ -15,7 +11,6 @@ module RuboCop
PATTERN
def on_send(node)
- return if in_spec?(node)
return unless includes_action_view_context?(node)
add_offense(node.arguments.first, location: :expression)
diff --git a/rubocop/cop/include_sidekiq_worker.rb b/rubocop/cop/include_sidekiq_worker.rb
index 8da4a147219..e69bc018add 100644
--- a/rubocop/cop/include_sidekiq_worker.rb
+++ b/rubocop/cop/include_sidekiq_worker.rb
@@ -1,11 +1,9 @@
-require_relative '../spec_helpers'
+# frozen_string_literal: true
module RuboCop
module Cop
# Cop that makes sure workers include `ApplicationWorker`, not `Sidekiq::Worker`.
class IncludeSidekiqWorker < RuboCop::Cop::Cop
- include SpecHelpers
-
MSG = 'Include `ApplicationWorker`, not `Sidekiq::Worker`.'.freeze
def_node_matcher :includes_sidekiq_worker?, <<~PATTERN
@@ -13,7 +11,6 @@ module RuboCop
PATTERN
def on_send(node)
- return if in_spec?(node)
return unless includes_sidekiq_worker?(node)
add_offense(node.arguments.first, location: :expression)
diff --git a/rubocop/cop/migration/add_limit_to_string_columns.rb b/rubocop/cop/migration/add_limit_to_string_columns.rb
new file mode 100644
index 00000000000..30affcbb089
--- /dev/null
+++ b/rubocop/cop/migration/add_limit_to_string_columns.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ # Cop that enforces length constraints to string columns
+ class AddLimitToStringColumns < RuboCop::Cop::Cop
+ include MigrationHelpers
+
+ ADD_COLUMNS_METHODS = %i(add_column add_column_with_default).freeze
+
+ MSG = 'String columns should have a limit constraint. 255 is suggested'.freeze
+
+ def on_def(node)
+ return unless in_migration?(node)
+
+ node.each_descendant(:send) do |send_node|
+ next unless string_operation?(send_node)
+
+ add_offense(send_node, location: :selector) unless limit_on_string_column?(send_node)
+ end
+ end
+
+ private
+
+ def string_operation?(node)
+ modifier = node.children[0]
+ migration_method = node.children[1]
+
+ if migration_method == :string
+ modifier.type == :lvar
+ elsif ADD_COLUMNS_METHODS.include?(migration_method)
+ modifier.nil? && string_column?(node.children[4])
+ end
+ end
+
+ def string_column?(column_type)
+ column_type.type == :sym && column_type.value == :string
+ end
+
+ def limit_on_string_column?(node)
+ migration_method = node.children[1]
+
+ if migration_method == :string
+ limit_present?(node.children)
+ elsif ADD_COLUMNS_METHODS.include?(migration_method)
+ limit_present?(node)
+ end
+ end
+
+ def limit_present?(statement)
+ !(statement.to_s =~ /:limit/).nil?
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/rspec/env_assignment.rb b/rubocop/cop/rspec/env_assignment.rb
index 8b61fa8e264..73e108c2232 100644
--- a/rubocop/cop/rspec/env_assignment.rb
+++ b/rubocop/cop/rspec/env_assignment.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helpers'
+# frozen_string_literal: true
module RuboCop
module Cop
@@ -17,8 +17,6 @@ module RuboCop
# stub_env('FOO', 'bar')
# end
class EnvAssignment < RuboCop::Cop::Cop
- include SpecHelpers
-
MESSAGE = "Don't assign to ENV, use `stub_env` instead.".freeze
def_node_search :env_assignment?, <<~PATTERN
@@ -28,7 +26,6 @@ module RuboCop
# Following is what node.children looks like on a match
# [s(:const, nil, :ENV), :[]=, s(:str, "key"), s(:str, "value")]
def on_send(node)
- return unless in_spec?(node)
return unless env_assignment?(node)
add_offense(node, location: :expression, message: MESSAGE)
diff --git a/rubocop/cop/rspec/factories_in_migration_specs.rb b/rubocop/cop/rspec/factories_in_migration_specs.rb
index 0c5aa838a2c..65c7638a0f4 100644
--- a/rubocop/cop/rspec/factories_in_migration_specs.rb
+++ b/rubocop/cop/rspec/factories_in_migration_specs.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helpers'
+# frozen_string_literal: true
module RuboCop
module Cop
@@ -14,8 +14,6 @@ module RuboCop
# let(:users) { table(:users) }
# let(:user) { users.create!(name: 'User 1', username: 'user1') }
class FactoriesInMigrationSpecs < RuboCop::Cop::Cop
- include SpecHelpers
-
MESSAGE = "Don't use FactoryBot.%s in migration specs, use `table` instead.".freeze
FORBIDDEN_METHODS = %i[build build_list create create_list].freeze
@@ -27,7 +25,6 @@ module RuboCop
# - Without FactoryBot namespace: [nil, :build, s(:sym, :user)]
# - With FactoryBot namespace: [s(:const, nil, :FactoryBot), :build, s(:sym, :user)]
def on_send(node)
- return unless in_migration_spec?(node)
return unless forbidden_factory_usage?(node)
method = node.children[1]
diff --git a/rubocop/cop/sidekiq_options_queue.rb b/rubocop/cop/sidekiq_options_queue.rb
index 253d2958866..499c712175e 100644
--- a/rubocop/cop/sidekiq_options_queue.rb
+++ b/rubocop/cop/sidekiq_options_queue.rb
@@ -1,11 +1,9 @@
-require_relative '../spec_helpers'
+# frozen_string_literal: true
module RuboCop
module Cop
# Cop that prevents manually setting a queue in Sidekiq workers.
class SidekiqOptionsQueue < RuboCop::Cop::Cop
- include SpecHelpers
-
MSG = 'Do not manually set a queue; `ApplicationWorker` sets one automatically.'.freeze
def_node_matcher :sidekiq_options?, <<~PATTERN
@@ -13,7 +11,6 @@ module RuboCop
PATTERN
def on_send(node)
- return if in_spec?(node)
return unless sidekiq_options?(node)
node.arguments.first.each_node(:pair) do |pair|
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 58a7ead6f13..d1328c4eb38 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -17,6 +17,7 @@ require_relative 'cop/migration/add_column'
require_relative 'cop/migration/add_concurrent_foreign_key'
require_relative 'cop/migration/add_concurrent_index'
require_relative 'cop/migration/add_index'
+require_relative 'cop/migration/add_limit_to_string_columns'
require_relative 'cop/migration/add_reference'
require_relative 'cop/migration/add_timestamps'
require_relative 'cop/migration/datetime'
diff --git a/rubocop/spec_helpers.rb b/rubocop/spec_helpers.rb
deleted file mode 100644
index ecd77c4351d..00000000000
--- a/rubocop/spec_helpers.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-module RuboCop
- module SpecHelpers
- SPEC_HELPERS = %w[fast_spec_helper.rb rails_helper.rb spec_helper.rb].freeze
- MIGRATION_SPEC_DIRECTORIES = ['spec/migrations', 'spec/lib/gitlab/background_migration'].freeze
-
- # Returns true if the given node originated from the spec directory.
- def in_spec?(node)
- path = node.location.expression.source_buffer.name
- pwd = RuboCop::PathUtil.pwd
-
- !SPEC_HELPERS.include?(File.basename(path)) &&
- path.start_with?(File.join(pwd, 'spec'), File.join(pwd, 'ee', 'spec'))
- end
-
- def migration_directories
- @migration_directories ||= MIGRATION_SPEC_DIRECTORIES.map do |dir|
- pwd = RuboCop::PathUtil.pwd
- [File.join(pwd, dir), File.join(pwd, 'ee', dir)]
- end.flatten
- end
-
- # Returns true if the given node originated from a migration spec.
- def in_migration_spec?(node)
- path = node.location.expression.source_buffer.name
-
- in_spec?(node) &&
- path.start_with?(*migration_directories)
- end
- end
-end
diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb
index 2d68a8e9fe3..6f553cadfa3 100644
--- a/spec/factories/ci/job_artifacts.rb
+++ b/spec/factories/ci/job_artifacts.rb
@@ -8,6 +8,10 @@ FactoryBot.define do
file_type :archive
file_format :zip
+ trait :expired do
+ expire_at { Date.yesterday }
+ end
+
trait :remote_store do
file_store JobArtifactUploader::Store::REMOTE
end
diff --git a/spec/factories/deploy_tokens.rb b/spec/factories/deploy_tokens.rb
index a96258f5cbe..99486acc2ab 100644
--- a/spec/factories/deploy_tokens.rb
+++ b/spec/factories/deploy_tokens.rb
@@ -2,7 +2,8 @@
FactoryBot.define do
factory :deploy_token do
- token { SecureRandom.hex(50) }
+ token nil
+ token_encrypted { Gitlab::CryptoHelper.aes256_gcm_encrypt( SecureRandom.hex(50) ) }
sequence(:name) { |n| "PDT #{n}" }
read_repository true
read_registry true
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index f362172e712..973d5a2dcfc 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -169,7 +169,7 @@ describe 'Dashboard Projects' do
expect(page).to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']")
expect(page).to have_css('.ci-status-link')
expect(page).to have_css('.ci-status-icon-success')
- expect(page).to have_link('Commit: passed')
+ expect(page).to have_link('Pipeline: passed')
end
end
@@ -189,7 +189,7 @@ describe 'Dashboard Projects' do
expect(page).not_to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']")
expect(page).not_to have_css('.ci-status-link')
expect(page).not_to have_css('.ci-status-icon-success')
- expect(page).not_to have_link('Commit: passed')
+ expect(page).not_to have_link('Pipeline: passed')
end
end
end
diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb
index a47eaa9bda7..c6e69fa3fb0 100644
--- a/spec/features/oauth_login_spec.rb
+++ b/spec/features/oauth_login_spec.rb
@@ -55,6 +55,18 @@ describe 'OAuth Login', :js, :allow_forgery_protection do
expect(current_path).to eq root_path
end
+
+ it 'when bypass-two-factor is enabled' do
+ allow(Gitlab.config.omniauth).to receive_messages(allow_bypass_two_factor: true)
+ login_via(provider.to_s, user, uid, remember_me: false)
+ expect(current_path).to eq root_path
+ end
+
+ it 'when bypass-two-factor is disabled' do
+ allow(Gitlab.config.omniauth).to receive_messages(allow_bypass_two_factor: false)
+ login_with_provider(provider, enter_two_factor: true)
+ expect(current_path).to eq root_path
+ end
end
context 'when "remember me" is checked' do
diff --git a/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb
index a1cad261875..fdc238d55cf 100644
--- a/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb
+++ b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb
@@ -18,7 +18,7 @@ describe 'Projects > Show > User sees last commit CI status' do
page.within '.blob-commit-info' do
expect(page).to have_content(project.commit.sha[0..6])
- expect(page).to have_link('Commit: skipped')
+ expect(page).to have_link('Pipeline: skipped')
end
end
end
diff --git a/spec/frontend/monitoring/embed/embed_spec.js b/spec/frontend/monitoring/embed/embed_spec.js
index 3b18a0f77c7..1ce14e2418a 100644
--- a/spec/frontend/monitoring/embed/embed_spec.js
+++ b/spec/frontend/monitoring/embed/embed_spec.js
@@ -1,7 +1,7 @@
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import Embed from '~/monitoring/components/embed.vue';
-import MonitorAreaChart from '~/monitoring/components/charts/area.vue';
+import MonitorTimeSeriesChart from '~/monitoring/components/charts/time_series.vue';
import { TEST_HOST } from 'helpers/test_constants';
import { groups, initialState, metricsData, metricsWithData } from './mock_data';
@@ -55,7 +55,7 @@ describe('Embed', () => {
it('shows an empty state when no metrics are present', () => {
expect(wrapper.find('.metrics-embed').exists()).toBe(true);
- expect(wrapper.find(MonitorAreaChart).exists()).toBe(false);
+ expect(wrapper.find(MonitorTimeSeriesChart).exists()).toBe(false);
});
});
@@ -71,8 +71,8 @@ describe('Embed', () => {
it('shows a chart when metrics are present', () => {
wrapper.setProps({});
expect(wrapper.find('.metrics-embed').exists()).toBe(true);
- expect(wrapper.find(MonitorAreaChart).exists()).toBe(true);
- expect(wrapper.findAll(MonitorAreaChart).length).toBe(2);
+ expect(wrapper.find(MonitorTimeSeriesChart).exists()).toBe(true);
+ expect(wrapper.findAll(MonitorTimeSeriesChart).length).toBe(2);
});
});
});
diff --git a/spec/graphql/resolvers/echo_resolver_spec.rb b/spec/graphql/resolvers/echo_resolver_spec.rb
new file mode 100644
index 00000000000..466501a4227
--- /dev/null
+++ b/spec/graphql/resolvers/echo_resolver_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::EchoResolver do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:text) { 'Message test' }
+
+ describe '#resolve' do
+ it 'echoes text and username' do
+ expect(resolve_echo(text)).to eq %Q("#{current_user.username}" says: #{text})
+ end
+
+ it 'echoes text and nil as username' do
+ expect(resolve_echo(text, { current_user: nil })).to eq "nil says: #{text}"
+ end
+ end
+
+ def resolve_echo(text, context = { current_user: current_user })
+ resolve(described_class, obj: nil, args: { text: text }, ctx: context)
+ end
+end
diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb
index bc2422aba90..4f665dc0514 100644
--- a/spec/helpers/ci_status_helper_spec.rb
+++ b/spec/helpers/ci_status_helper_spec.rb
@@ -53,4 +53,80 @@ describe CiStatusHelper do
expect(helper.pipeline_status_cache_key(pipeline_status)).to eq("pipeline-status/123abc-success")
end
end
+
+ describe "#render_status_with_link" do
+ subject { helper.render_status_with_link("success") }
+
+ it "renders a passed status icon" do
+ is_expected.to include("<span class=\"ci-status-link ci-status-icon-success d-inline-flex")
+ end
+
+ it "has 'Pipeline' as the status type in the title" do
+ is_expected.to include("title=\"Pipeline: passed\"")
+ end
+
+ it "has the success status icon" do
+ is_expected.to include("ci-status-icon-success")
+ end
+
+ context "when pipeline has commit path" do
+ subject { helper.render_status_with_link("success", "/commit-path") }
+
+ it "links to commit" do
+ is_expected.to include("href=\"/commit-path\"")
+ end
+
+ it "does not contain a span element" do
+ is_expected.not_to include("<span")
+ end
+
+ it "has 'Pipeline' as the status type in the title" do
+ is_expected.to include("title=\"Pipeline: passed\"")
+ end
+
+ it "has the correct status icon" do
+ is_expected.to include("ci-status-icon-success")
+ end
+ end
+
+ context "when different type than pipeline is provided" do
+ subject { helper.render_status_with_link("success", type: "commit") }
+
+ it "has the provided type in the title" do
+ is_expected.to include("title=\"Commit: passed\"")
+ end
+ end
+
+ context "when tooltip_placement is provided" do
+ subject { helper.render_status_with_link("success", tooltip_placement: "right") }
+
+ it "has the provided tooltip placement" do
+ is_expected.to include("data-placement=\"right\"")
+ end
+ end
+
+ context "when additional CSS classes are provided" do
+ subject { helper.render_status_with_link("success", cssclass: "extra-class") }
+
+ it "has appended extra class to icon classes" do
+ is_expected.to include("class=\"ci-status-link ci-status-icon-success d-inline-flex extra-class\"")
+ end
+ end
+
+ context "when container is provided" do
+ subject { helper.render_status_with_link("success", container: "my-container") }
+
+ it "has the provided container in data" do
+ is_expected.to include("data-container=\"my-container\"")
+ end
+ end
+
+ context "when icon_size is provided" do
+ subject { helper.render_status_with_link("success", icon_size: 24) }
+
+ it "has the svg class to change size" do
+ is_expected.to include("<svg class=\"s24\">")
+ end
+ end
+ end
end
diff --git a/spec/javascripts/monitoring/panel_type_spec.js b/spec/javascripts/monitoring/panel_type_spec.js
index 086be628093..a2366e74d43 100644
--- a/spec/javascripts/monitoring/panel_type_spec.js
+++ b/spec/javascripts/monitoring/panel_type_spec.js
@@ -1,7 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import PanelType from '~/monitoring/components/panel_type.vue';
import EmptyChart from '~/monitoring/components/charts/empty_chart.vue';
-import AreaChart from '~/monitoring/components/charts/area.vue';
+import TimeSeriesChart from '~/monitoring/components/charts/time_series.vue';
import { graphDataPrometheusQueryRange } from './mock_data';
import { createStore } from '~/monitoring/stores';
@@ -62,9 +62,10 @@ describe('Panel Type component', () => {
});
});
- describe('Area Chart panel type', () => {
+ describe('Time Series Chart panel type', () => {
it('is rendered', () => {
- expect(panelType.find(AreaChart).exists()).toBe(true);
+ expect(panelType.find(TimeSeriesChart).isVueInstance()).toBe(true);
+ expect(panelType.find(TimeSeriesChart).exists()).toBe(true);
});
it('sets clipboard text on the dropdown', () => {
diff --git a/spec/javascripts/notes/stores/actions_spec.js b/spec/javascripts/notes/stores/actions_spec.js
index e55aa0e965a..1fd4a9a7612 100644
--- a/spec/javascripts/notes/stores/actions_spec.js
+++ b/spec/javascripts/notes/stores/actions_spec.js
@@ -336,7 +336,7 @@ describe('Actions Notes Store', () => {
});
});
- describe('deleteNote', () => {
+ describe('removeNote', () => {
const endpoint = `${TEST_HOST}/note`;
let axiosMock;
@@ -357,7 +357,7 @@ describe('Actions Notes Store', () => {
const note = { path: endpoint, id: 1 };
testAction(
- actions.deleteNote,
+ actions.removeNote,
note,
store.state,
[
@@ -384,7 +384,7 @@ describe('Actions Notes Store', () => {
$('body').attr('data-page', 'projects:merge_requests:show');
testAction(
- actions.deleteNote,
+ actions.removeNote,
note,
store.state,
[
@@ -409,6 +409,45 @@ describe('Actions Notes Store', () => {
});
});
+ describe('deleteNote', () => {
+ const endpoint = `${TEST_HOST}/note`;
+ let axiosMock;
+
+ beforeEach(() => {
+ axiosMock = new AxiosMockAdapter(axios);
+ axiosMock.onDelete(endpoint).replyOnce(200, {});
+
+ $('body').attr('data-page', '');
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+
+ $('body').attr('data-page', '');
+ });
+
+ it('dispatches removeNote', done => {
+ const note = { path: endpoint, id: 1 };
+
+ testAction(
+ actions.deleteNote,
+ note,
+ {},
+ [],
+ [
+ {
+ type: 'removeNote',
+ payload: {
+ id: 1,
+ path: 'http://test.host/note',
+ },
+ },
+ ],
+ done,
+ );
+ });
+ });
+
describe('createNewNote', () => {
describe('success', () => {
const res = {
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
new file mode 100644
index 00000000000..29f4be76a65
--- /dev/null
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent do
+ it { expect(described_class).to respond_to(:name) }
+ it { expect(described_class).to respond_to(:identifier) }
+
+ it { expect(described_class.new({})).to respond_to(:object_type) }
+end
diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb
index a9b15c411dc..1e3da4f7c2d 100644
--- a/spec/lib/gitlab/auth/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb
@@ -787,11 +787,25 @@ describe Gitlab::Auth::OAuth::User do
end
end
- describe '#bypass_two_factor?' do
- subject { oauth_user.bypass_two_factor? }
+ describe "#bypass_two_factor?" do
+ it "when with allow_bypass_two_factor disabled (Default)" do
+ stub_omniauth_config(allow_bypass_two_factor: false)
+ expect(oauth_user.bypass_two_factor?).to be_falsey
+ end
+
+ it "when with allow_bypass_two_factor enabled" do
+ stub_omniauth_config(allow_bypass_two_factor: true)
+ expect(oauth_user.bypass_two_factor?).to be_truthy
+ end
+
+ it "when provider in allow_bypass_two_factor array" do
+ stub_omniauth_config(allow_bypass_two_factor: [provider])
+ expect(oauth_user.bypass_two_factor?).to be_truthy
+ end
- it 'returns always false' do
- is_expected.to be_falsey
+ it "when provider not in allow_bypass_two_factor array" do
+ stub_omniauth_config(allow_bypass_two_factor: ["foo"])
+ expect(oauth_user.bypass_two_factor?).to be_falsey
end
end
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 2731fc8573f..cff4eb398bf 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -576,6 +576,38 @@ describe Gitlab::Database::MigrationHelpers do
model.rename_column_concurrently(:users, :old, :new)
end
+
+ context 'when default is false' do
+ let(:old_column) do
+ double(:column,
+ type: :boolean,
+ limit: nil,
+ default: false,
+ null: false,
+ precision: nil,
+ scale: nil)
+ end
+
+ it 'copies the default to the new column' do
+ expect(model).to receive(:change_column_default)
+ .with(:users, :new, old_column.default)
+
+ model.rename_column_concurrently(:users, :old, :new)
+ end
+ end
+ end
+ end
+
+ describe '#undo_rename_column_concurrently' do
+ it 'reverses the operations of rename_column_concurrently' do
+ expect(model).to receive(:check_trigger_permissions!).with(:users)
+
+ expect(model).to receive(:remove_rename_triggers_for_postgresql)
+ .with(:users, /trigger_.{12}/)
+
+ expect(model).to receive(:remove_column).with(:users, :new)
+
+ model.undo_rename_column_concurrently(:users, :old, :new)
end
end
@@ -592,6 +624,80 @@ describe Gitlab::Database::MigrationHelpers do
end
end
+ describe '#undo_cleanup_concurrent_column_rename' do
+ context 'in a transaction' do
+ it 'raises RuntimeError' do
+ allow(model).to receive(:transaction_open?).and_return(true)
+
+ expect { model.undo_cleanup_concurrent_column_rename(:users, :old, :new) }
+ .to raise_error(RuntimeError)
+ end
+ end
+
+ context 'outside a transaction' do
+ let(:new_column) do
+ double(:column,
+ type: :integer,
+ limit: 8,
+ default: 0,
+ null: false,
+ precision: 5,
+ scale: 1)
+ end
+
+ let(:trigger_name) { model.rename_trigger_name(:users, :old, :new) }
+
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ allow(model).to receive(:column_for).and_return(new_column)
+ end
+
+ it 'reverses the operations of cleanup_concurrent_column_rename' do
+ expect(model).to receive(:check_trigger_permissions!).with(:users)
+
+ expect(model).to receive(:install_rename_triggers_for_postgresql)
+ .with(trigger_name, '"users"', '"old"', '"new"')
+
+ expect(model).to receive(:add_column)
+ .with(:users, :old, :integer,
+ limit: new_column.limit,
+ precision: new_column.precision,
+ scale: new_column.scale)
+
+ expect(model).to receive(:change_column_default)
+ .with(:users, :old, new_column.default)
+
+ expect(model).to receive(:update_column_in_batches)
+
+ expect(model).to receive(:change_column_null).with(:users, :old, false)
+
+ expect(model).to receive(:copy_indexes).with(:users, :new, :old)
+ expect(model).to receive(:copy_foreign_keys).with(:users, :new, :old)
+
+ model.undo_cleanup_concurrent_column_rename(:users, :old, :new)
+ end
+
+ context 'when default is false' do
+ let(:new_column) do
+ double(:column,
+ type: :boolean,
+ limit: nil,
+ default: false,
+ null: false,
+ precision: nil,
+ scale: nil)
+ end
+
+ it 'copies the default to the old column' do
+ expect(model).to receive(:change_column_default)
+ .with(:users, :old, new_column.default)
+
+ model.undo_cleanup_concurrent_column_rename(:users, :old, :new)
+ end
+ end
+ end
+ end
+
describe '#change_column_type_concurrently' do
it 'changes the column type' do
expect(model).to receive(:rename_column_concurrently)
@@ -619,10 +725,18 @@ describe Gitlab::Database::MigrationHelpers do
.with(/CREATE OR REPLACE FUNCTION foo()/m)
expect(model).to receive(:execute)
+ .with(/DROP TRIGGER IF EXISTS foo/m)
+
+ expect(model).to receive(:execute)
.with(/CREATE TRIGGER foo/m)
model.install_rename_triggers_for_postgresql('foo', :users, :old, :new)
end
+
+ it 'does not fail if trigger already exists' do
+ model.install_rename_triggers_for_postgresql('foo', :users, :old, :new)
+ model.install_rename_triggers_for_postgresql('foo', :users, :old, :new)
+ end
end
describe '#remove_rename_triggers_for_postgresql' do
diff --git a/spec/services/self_monitoring/project/create_service_spec.rb b/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb
index def20448bd9..9bd0d800086 100644
--- a/spec/services/self_monitoring/project/create_service_spec.rb
+++ b/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb
@@ -2,29 +2,48 @@
require 'spec_helper'
-describe SelfMonitoring::Project::CreateService do
+describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
describe '#execute' do
- let(:result) { subject.execute }
+ let(:result) { subject.execute! }
let(:prometheus_settings) do
- OpenStruct.new(
+ {
enable: true,
listen_address: 'localhost:9090'
- )
+ }
end
before do
- allow(Gitlab.config).to receive(:prometheus).and_return(prometheus_settings)
+ stub_config(prometheus: prometheus_settings)
+ end
+
+ context 'without application_settings' do
+ it 'does not fail' do
+ expect(subject).to receive(:log_error).and_call_original
+ expect(result).to eq(
+ status: :success
+ )
+
+ expect(Project.count).to eq(0)
+ expect(Group.count).to eq(0)
+ end
end
context 'without admin users' do
- it 'returns error' do
+ let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
+
+ before do
+ allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
+ end
+
+ it 'does not fail' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
- status: :error,
- message: 'No active admin user found',
- failed_step: :validate_admins
+ status: :success
)
+
+ expect(Project.count).to eq(0)
+ expect(Group.count).to eq(0)
end
end
@@ -36,6 +55,7 @@ describe SelfMonitoring::Project::CreateService do
let!(:user) { create(:user, :admin) }
before do
+ allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
application_setting.allow_local_requests_from_web_hooks_and_services = true
end
@@ -56,8 +76,8 @@ describe SelfMonitoring::Project::CreateService do
it 'creates group' do
expect(result[:status]).to eq(:success)
expect(group).to be_persisted
- expect(group.name).to eq(described_class::GROUP_NAME)
- expect(group.path).to start_with(described_class::GROUP_PATH)
+ expect(group.name).to eq('GitLab Instance Administrators')
+ expect(group.path).to start_with('gitlab-instance-administrators')
expect(group.path.split('-').last.length).to eq(8)
expect(group.visibility_level).to eq(described_class::VISIBILITY_LEVEL)
end
@@ -77,9 +97,16 @@ describe SelfMonitoring::Project::CreateService do
end
it 'creates project with correct name and description' do
+ path = 'administration/monitoring/gitlab_instance_administration_project/index'
+ docs_path = Rails.application.routes.url_helpers.help_page_path(path)
+
expect(result[:status]).to eq(:success)
expect(project.name).to eq(described_class::PROJECT_NAME)
- expect(project.description).to eq(described_class::PROJECT_DESCRIPTION)
+ expect(project.description).to eq(
+ 'This project is automatically generated and will be used to help monitor this GitLab instance. ' \
+ "[More information](#{docs_path})"
+ )
+ expect(File).to exist("doc/#{path}.md")
end
it 'adds all admins as maintainers' do
@@ -105,19 +132,30 @@ describe SelfMonitoring::Project::CreateService do
it 'returns error when saving project ID fails' do
allow(application_setting).to receive(:update) { false }
- expect(result[:status]).to eq(:error)
- expect(result[:failed_step]).to eq(:save_project_id)
- expect(result[:message]).to eq('Could not save project ID')
+ expect { result }.to raise_error(StandardError, 'Could not save project ID')
end
- it 'does not fail when a project already exists' do
- expect(result[:status]).to eq(:success)
+ context 'when project already exists' do
+ let(:existing_group) { create(:group) }
+ let(:existing_project) { create(:project, namespace: existing_group) }
- second_result = subject.execute
+ before do
+ admin1 = create(:user, :admin)
+ admin2 = create(:user, :admin)
+
+ existing_group.add_owner(user)
+ existing_group.add_users([admin1, admin2], Gitlab::Access::MAINTAINER)
+
+ application_setting.instance_administration_project_id = existing_project.id
+ end
+
+ it 'does not fail' do
+ expect(subject).to receive(:log_error).and_call_original
+ expect(result[:status]).to eq(:success)
- expect(second_result[:status]).to eq(:success)
- expect(second_result[:project]).to eq(project)
- expect(second_result[:group]).to eq(group)
+ expect(Project.count).to eq(1)
+ expect(Group.count).to eq(1)
+ end
end
context 'when local requests from hooks and services are not allowed' do
@@ -138,8 +176,11 @@ describe SelfMonitoring::Project::CreateService do
end
context 'with non default prometheus address' do
- before do
- prometheus_settings.listen_address = 'https://localhost:9090'
+ let(:prometheus_settings) do
+ {
+ enable: true,
+ listen_address: 'https://localhost:9090'
+ }
end
it_behaves_like 'has prometheus service', 'https://localhost:9090'
@@ -157,8 +198,11 @@ describe SelfMonitoring::Project::CreateService do
end
context 'when prometheus setting is disabled in gitlab.yml' do
- before do
- prometheus_settings.enable = false
+ let(:prometheus_settings) do
+ {
+ enable: false,
+ listen_address: 'http://localhost:9090'
+ }
end
it 'does not configure prometheus' do
@@ -168,9 +212,7 @@ describe SelfMonitoring::Project::CreateService do
end
context 'when prometheus listen address is blank in gitlab.yml' do
- before do
- prometheus_settings.listen_address = ''
- end
+ let(:prometheus_settings) { { enable: true, listen_address: '' } }
it 'does not configure prometheus' do
expect(result).to include(status: :success)
@@ -192,11 +234,7 @@ describe SelfMonitoring::Project::CreateService do
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
- expect(result).to eq({
- status: :error,
- message: 'Could not create project',
- failed_step: :create_project
- })
+ expect { result }.to raise_error(StandardError, 'Could not create project')
end
end
@@ -207,26 +245,21 @@ describe SelfMonitoring::Project::CreateService do
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
- expect(result).to eq({
- status: :error,
- message: 'Could not add admins as members',
- failed_step: :add_group_members
- })
+ expect { result }.to raise_error(StandardError, 'Could not add admins as members')
end
end
context 'when prometheus manual configuration cannot be saved' do
- before do
- prometheus_settings.listen_address = 'httpinvalid://localhost:9090'
+ let(:prometheus_settings) do
+ {
+ enable: true,
+ listen_address: 'httpinvalid://localhost:9090'
+ }
end
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
- expect(result).to eq(
- status: :error,
- message: 'Could not save prometheus manual configuration',
- failed_step: :add_prometheus_manual_configuration
- )
+ expect { result }.to raise_error(StandardError, 'Could not save prometheus manual configuration')
end
end
end
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 77e58b6d5c7..8d37de32179 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -347,6 +347,17 @@ describe Gitlab::Database do
pool.disconnect!
end
end
+
+ it 'allows setting of a custom hostname and port' do
+ pool = described_class.create_connection_pool(5, '127.0.0.1', 5432)
+
+ begin
+ expect(pool.spec.config[:host]).to eq('127.0.0.1')
+ expect(pool.spec.config[:port]).to eq(5432)
+ ensure
+ pool.disconnect!
+ end
+ end
end
describe '.cached_column_exists?' do
diff --git a/spec/lib/gitlab/fogbugz_import/project_creator_spec.rb b/spec/lib/gitlab/fogbugz_import/project_creator_spec.rb
new file mode 100644
index 00000000000..503fe897e29
--- /dev/null
+++ b/spec/lib/gitlab/fogbugz_import/project_creator_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::FogbugzImport::ProjectCreator do
+ let(:user) { create(:user) }
+
+ let(:repo) do
+ instance_double(Gitlab::FogbugzImport::Repository,
+ name: 'Vim',
+ safe_name: 'vim',
+ path: 'vim',
+ raw_data: '')
+ end
+
+ let(:uri) { 'https://testing.fogbugz.com' }
+ let(:token) { 'token' }
+ let(:fb_session) { { uri: uri, token: token } }
+ let(:project_creator) { described_class.new(repo, fb_session, user.namespace, user) }
+
+ subject do
+ project_creator.execute
+ end
+
+ it 'creates project with private visibility level' do
+ expect(subject.persisted?).to eq(true)
+ expect(subject.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+end
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 d60d1b7559a..7a7ae373058 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
@@ -30,7 +30,10 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
describe '#authorized_resolve' do
let(:presented_object) { double('presented object') }
let(:presented_type) { double('parent type', object: presented_object) }
- subject(:resolved) { service.authorized_resolve.call(presented_type, {}, { current_user: current_user }) }
+ 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) }
+ subject(:resolved) { service.authorized_resolve.call(presented_type, {}, context) }
context 'scalar types' do
shared_examples 'checking permissions on the presented object' do
diff --git a/spec/lib/gitlab/graphql/markdown_field_spec.rb b/spec/lib/gitlab/graphql/markdown_field_spec.rb
index a8566aa8e1c..866a20801d3 100644
--- a/spec/lib/gitlab/graphql/markdown_field_spec.rb
+++ b/spec/lib/gitlab/graphql/markdown_field_spec.rb
@@ -30,17 +30,20 @@ describe Gitlab::Graphql::MarkdownField do
let(:note) { build(:note, note: '# Markdown!') }
let(:thing_with_markdown) { double('markdown thing', object: note) }
let(:expected_markdown) { '<h1 data-sourcepos="1:1-1:11" dir="auto">Markdown!</h1>' }
+ 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: nil, object: nil) }
it 'renders markdown from the same property as the field name without the `_html` suffix' do
field = class_with_markdown_field(:note_html, null: false).fields['noteHtml']
- expect(field.to_graphql.resolve(thing_with_markdown, {}, {})).to eq(expected_markdown)
+ expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown)
end
it 'renders markdown from a specific property when a `method` argument is passed' do
field = class_with_markdown_field(:test_html, null: false, method: :note).fields['testHtml']
- expect(field.to_graphql.resolve(thing_with_markdown, {}, {})).to eq(expected_markdown)
+ expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown)
end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/merge_request_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/merge_request_counter_spec.rb
new file mode 100644
index 00000000000..4be4a661260
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/merge_request_counter_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::UsageDataCounters::MergeRequestCounter do
+ it_behaves_like 'a redis usage counter', 'Merge Request', :create
+
+ it_behaves_like 'a redis usage counter with totals', :merge_request, create: 5
+end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index dda119e09b1..b3a179e276b 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -69,6 +69,7 @@ describe Gitlab::UsageData do
snippet_update: a_kind_of(Integer),
snippet_comment: a_kind_of(Integer),
merge_request_comment: a_kind_of(Integer),
+ merge_request_create: a_kind_of(Integer),
commit_comment: a_kind_of(Integer),
wiki_pages_create: a_kind_of(Integer),
wiki_pages_update: a_kind_of(Integer),
diff --git a/spec/migrations/add_gitlab_instance_administration_project_spec.rb b/spec/migrations/add_gitlab_instance_administration_project_spec.rb
new file mode 100644
index 00000000000..08e20a4e8ff
--- /dev/null
+++ b/spec/migrations/add_gitlab_instance_administration_project_spec.rb
@@ -0,0 +1,252 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20190801072937_add_gitlab_instance_administration_project.rb')
+
+describe AddGitlabInstanceAdministrationProject, :migration do
+ let(:application_settings) { table(:application_settings) }
+ let(:users) { table(:users) }
+ let(:projects) { table(:projects) }
+ let(:namespaces) { table(:namespaces) }
+ let(:members) { table(:members) }
+
+ let(:service_class) do
+ Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService
+ end
+
+ let(:prometheus_settings) do
+ {
+ enable: true,
+ listen_address: 'localhost:9090'
+ }
+ end
+
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+
+ stub_config(prometheus: prometheus_settings)
+ end
+
+ describe 'down' do
+ let!(:application_setting) { application_settings.create! }
+ let!(:user) { users.create!(admin: true, email: 'admin1@example.com', projects_limit: 10, state: :active) }
+
+ it 'deletes group and project' do
+ migrate!
+
+ expect(Project.count).to eq(1)
+ expect(Group.count).to eq(1)
+
+ schema_migrate_down!
+
+ expect(Project.count).to eq(0)
+ expect(Group.count).to eq(0)
+ end
+ end
+
+ describe 'up' do
+ context 'without application_settings' do
+ it 'does not fail' do
+ migrate!
+
+ expect(Project.count).to eq(0)
+ end
+ end
+
+ context 'without admin users' do
+ let!(:application_setting) { application_settings.create! }
+
+ it 'does not fail' do
+ migrate!
+
+ expect(Project.count).to eq(0)
+ end
+ end
+
+ context 'with admin users' do
+ let(:project) { Project.last }
+ let(:group) { Group.last }
+ let!(:application_setting) { application_settings.create! }
+ let!(:user) { users.create!(admin: true, email: 'admin1@example.com', projects_limit: 10, state: :active) }
+
+ before do
+ stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
+ end
+
+ shared_examples 'has prometheus service' do |listen_address|
+ it do
+ migrate!
+
+ prometheus = project.prometheus_service
+ expect(prometheus).to be_persisted
+ expect(prometheus).not_to eq(nil)
+ expect(prometheus.api_url).to eq(listen_address)
+ expect(prometheus.active).to eq(true)
+ expect(prometheus.manual_configuration).to eq(true)
+ end
+ end
+
+ it_behaves_like 'has prometheus service', 'http://localhost:9090'
+
+ it 'creates GitLab Instance Administrator group' do
+ migrate!
+
+ expect(group).to be_persisted
+ expect(group.name).to eq('GitLab Instance Administrators')
+ expect(group.path).to start_with('gitlab-instance-administrators')
+ expect(group.path.split('-').last.length).to eq(8)
+ expect(group.visibility_level).to eq(service_class::VISIBILITY_LEVEL)
+ end
+
+ it 'creates project with internal visibility' do
+ migrate!
+
+ expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
+ expect(project).to be_persisted
+ end
+
+ it 'creates project with correct name and description' do
+ migrate!
+
+ path = 'administration/monitoring/gitlab_instance_administration_project/index'
+ docs_path = Rails.application.routes.url_helpers.help_page_path(path)
+
+ expect(project.name).to eq(service_class::PROJECT_NAME)
+ expect(project.description).to eq(
+ 'This project is automatically generated and will be used to help monitor this GitLab instance. ' \
+ "[More information](#{docs_path})"
+ )
+ expect(File).to exist("doc/#{path}.md")
+ end
+
+ it 'adds all admins as maintainers' do
+ admin1 = users.create!(admin: true, email: 'admin2@example.com', projects_limit: 10, state: :active)
+ admin2 = users.create!(admin: true, email: 'admin3@example.com', projects_limit: 10, state: :active)
+ users.create!(email: 'nonadmin1@example.com', projects_limit: 10, state: :active)
+
+ migrate!
+
+ expect(project.owner).to eq(group)
+ expect(group.members.collect(&:user).collect(&:id)).to contain_exactly(user.id, admin1.id, admin2.id)
+ expect(group.members.collect(&:access_level)).to contain_exactly(
+ Gitlab::Access::OWNER,
+ Gitlab::Access::MAINTAINER,
+ Gitlab::Access::MAINTAINER
+ )
+ end
+
+ it 'saves the project id' do
+ migrate!
+
+ application_setting.reload
+ expect(application_setting.instance_administration_project_id).to eq(project.id)
+ end
+
+ it 'does not fail when a project already exists' do
+ group = namespaces.create!(
+ path: 'gitlab-instance-administrators',
+ name: 'GitLab Instance Administrators',
+ type: 'Group'
+ )
+ project = projects.create!(
+ namespace_id: group.id,
+ name: 'GitLab Instance Administration'
+ )
+
+ admin1 = users.create!(admin: true, email: 'admin4@example.com', projects_limit: 10, state: :active)
+ admin2 = users.create!(admin: true, email: 'admin5@example.com', projects_limit: 10, state: :active)
+
+ members.create!(
+ user_id: admin1.id,
+ source_id: group.id,
+ source_type: 'Namespace',
+ type: 'GroupMember',
+ access_level: GroupMember::MAINTAINER,
+ notification_level: NotificationSetting.levels[:global]
+ )
+ members.create!(
+ user_id: admin2.id,
+ source_id: group.id,
+ source_type: 'Namespace',
+ type: 'GroupMember',
+ access_level: GroupMember::MAINTAINER,
+ notification_level: NotificationSetting.levels[:global]
+ )
+
+ stub_application_setting(instance_administration_project: project)
+
+ migrate!
+
+ expect(Project.last.id).to eq(project.id)
+ expect(Group.last.id).to eq(group.id)
+ end
+
+ context 'when local requests from hooks and services are not allowed' do
+ before do
+ stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
+ end
+
+ it_behaves_like 'has prometheus service', 'http://localhost:9090'
+
+ it 'does not overwrite the existing whitelist' do
+ application_setting.update!(outbound_local_requests_whitelist: ['example.com'])
+
+ migrate!
+
+ application_setting.reload
+ expect(application_setting.outbound_local_requests_whitelist).to contain_exactly(
+ 'example.com', 'localhost'
+ )
+ end
+ end
+
+ context 'with non default prometheus address' do
+ let(:prometheus_settings) do
+ {
+ enable: true,
+ listen_address: 'https://localhost:9090'
+ }
+ end
+
+ it_behaves_like 'has prometheus service', 'https://localhost:9090'
+ end
+
+ context 'when prometheus setting is not present in gitlab.yml' do
+ before do
+ allow(Gitlab.config).to receive(:prometheus).and_raise(Settingslogic::MissingSetting)
+ end
+
+ it 'does not fail' do
+ migrate!
+
+ expect(project.prometheus_service).to be_nil
+ end
+ end
+
+ context 'when prometheus setting is disabled in gitlab.yml' do
+ let(:prometheus_settings) do
+ {
+ enable: false,
+ listen_address: 'localhost:9090'
+ }
+ end
+
+ it 'does not configure prometheus' do
+ migrate!
+
+ expect(project.prometheus_service).to be_nil
+ end
+ end
+
+ context 'when prometheus listen address is blank in gitlab.yml' do
+ let(:prometheus_settings) { { enable: true, listen_address: '' } }
+
+ it 'does not configure prometheus' do
+ migrate!
+
+ expect(project.prometheus_service).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/encrypt_deploy_tokens_tokens_spec.rb b/spec/migrations/encrypt_deploy_tokens_tokens_spec.rb
new file mode 100644
index 00000000000..a398e079731
--- /dev/null
+++ b/spec/migrations/encrypt_deploy_tokens_tokens_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require Rails.root.join('db', 'post_migrate', '20190711201818_encrypt_deploy_tokens_tokens.rb')
+
+describe EncryptDeployTokensTokens, :migration do
+ let(:migration) { described_class.new }
+ let(:deployment_tokens) { table(:deploy_tokens) }
+ let(:plaintext) { "secret-token" }
+ let(:expires_at) { DateTime.now + 1.year }
+ let(:ciphertext) { Gitlab::CryptoHelper.aes256_gcm_encrypt(plaintext) }
+
+ describe '#up' do
+ it 'keeps plaintext token the same and populates token_encrypted if not present' do
+ deploy_token = deployment_tokens.create!(
+ name: 'test_token',
+ read_repository: true,
+ expires_at: expires_at,
+ username: 'gitlab-token-1',
+ token: plaintext
+ )
+
+ migration.up
+
+ expect(deploy_token.reload.token).to eq(plaintext)
+ expect(deploy_token.reload.token_encrypted).to eq(ciphertext)
+ end
+ end
+
+ describe '#down' do
+ it 'decrypts encrypted token and saves it' do
+ deploy_token = deployment_tokens.create!(
+ name: 'test_token',
+ read_repository: true,
+ expires_at: expires_at,
+ username: 'gitlab-token-1',
+ token_encrypted: ciphertext
+ )
+
+ migration.down
+
+ expect(deploy_token.reload.token).to eq(plaintext)
+ expect(deploy_token.reload.token_encrypted).to eq(ciphertext)
+ end
+ end
+end
diff --git a/spec/models/analytics/cycle_analytics/project_stage_spec.rb b/spec/models/analytics/cycle_analytics/project_stage_spec.rb
index 4e3923e82b1..83d6ff754c5 100644
--- a/spec/models/analytics/cycle_analytics/project_stage_spec.rb
+++ b/spec/models/analytics/cycle_analytics/project_stage_spec.rb
@@ -6,4 +6,18 @@ describe Analytics::CycleAnalytics::ProjectStage do
describe 'associations' do
it { is_expected.to belong_to(:project) }
end
+
+ it 'default stages must be valid' do
+ project = create(:project)
+
+ Gitlab::Analytics::CycleAnalytics::DefaultStages.all.each do |params|
+ stage = described_class.new(params.merge(project: project))
+ expect(stage).to be_valid
+ end
+ end
+
+ it_behaves_like "cycle analytics stage" do
+ let(:parent) { create(:project) }
+ let(:parent_name) { :project }
+ end
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index d4e631f109b..51ed8e9421b 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -322,4 +322,30 @@ describe Deployment do
end
end
end
+
+ describe '#deployed_by' do
+ it 'returns the deployment user if there is no deployable' do
+ deployment_user = create(:user)
+ deployment = create(:deployment, deployable: nil, user: deployment_user)
+
+ expect(deployment.deployed_by).to eq(deployment_user)
+ end
+
+ it 'returns the deployment user if the deployable have no user' do
+ deployment_user = create(:user)
+ build = create(:ci_build, user: nil)
+ deployment = create(:deployment, deployable: build, user: deployment_user)
+
+ expect(deployment.deployed_by).to eq(deployment_user)
+ end
+
+ it 'returns the deployable user if there is one' do
+ build_user = create(:user)
+ deployment_user = create(:user)
+ build = create(:ci_build, user: build_user)
+ deployment = create(:deployment, deployable: build, user: deployment_user)
+
+ expect(deployment.deployed_by).to eq(build_user)
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index ff9e94afc12..bd352db2236 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -4877,35 +4877,22 @@ describe Project do
describe '#git_objects_poolable?' do
subject { project }
-
- context 'when the feature flag is turned off' do
- before do
- stub_feature_flags(object_pools: false)
- end
-
- let(:project) { create(:project, :repository, :public) }
+ context 'when not using hashed storage' do
+ let(:project) { create(:project, :legacy_storage, :public, :repository) }
it { is_expected.not_to be_git_objects_poolable }
end
- context 'when the feature flag is enabled' do
- context 'when not using hashed storage' do
- let(:project) { create(:project, :legacy_storage, :public, :repository) }
-
- it { is_expected.not_to be_git_objects_poolable }
- end
+ context 'when the project is not public' do
+ let(:project) { create(:project, :private) }
- context 'when the project is not public' do
- let(:project) { create(:project, :private) }
-
- it { is_expected.not_to be_git_objects_poolable }
- end
+ it { is_expected.not_to be_git_objects_poolable }
+ end
- context 'when objects are poolable' do
- let(:project) { create(:project, :repository, :public) }
+ context 'when objects are poolable' do
+ let(:project) { create(:project, :repository, :public) }
- it { is_expected.to be_git_objects_poolable }
- end
+ it { is_expected.to be_git_objects_poolable }
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 46b86e8393d..8338d2b5b39 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -103,6 +103,14 @@ describe User do
it { is_expected.to validate_length_of(:name).is_at_most(128) }
end
+ describe 'first name' do
+ it { is_expected.to validate_length_of(:first_name).is_at_most(255) }
+ end
+
+ describe 'last name' do
+ it { is_expected.to validate_length_of(:last_name).is_at_most(255) }
+ end
+
describe 'username' do
it 'validates presence' do
expect(subject).to validate_presence_of(:username)
@@ -678,6 +686,18 @@ describe User do
end
end
+ describe 'name getters' do
+ let(:user) { create(:user, name: 'Kane Martin William') }
+
+ it 'derives first name from full name, if not present' do
+ expect(user.first_name).to eq('Kane')
+ end
+
+ it 'derives last name from full name, if not present' do
+ expect(user.last_name).to eq('Martin William')
+ end
+ end
+
describe '#highest_role' do
let(:user) { create(:user) }
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 8fd54e0bf1d..71ba73d5661 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -94,6 +94,19 @@ describe ProjectPolicy do
permissions.each { |p| is_expected.not_to be_allowed(p) }
end
+ context 'with no project feature' do
+ subject { described_class.new(owner, project) }
+
+ before do
+ project.project_feature.destroy
+ project.reload
+ end
+
+ it 'returns false' do
+ is_expected.to be_disallowed(:read_build)
+ end
+ end
+
it 'does not include the read_issue permission when the issue author is not a member of the private project' do
project = create(:project, :private)
issue = create(:issue, project: project, author: create(:user))
diff --git a/spec/requests/api/graphql/multiplexed_queries_spec.rb b/spec/requests/api/graphql/multiplexed_queries_spec.rb
index 844fd979285..9ebb57f6b9c 100644
--- a/spec/requests/api/graphql/multiplexed_queries_spec.rb
+++ b/spec/requests/api/graphql/multiplexed_queries_spec.rb
@@ -6,9 +6,9 @@ describe 'Multiplexed queries' do
it 'returns responses for multiple queries' do
queries = [
- { query: 'query($text: String) { echo(text: $text) }',
+ { query: 'query($text: String!) { echo(text: $text) }',
variables: { 'text' => 'Hello' } },
- { query: 'query($text: String) { echo(text: $text) }',
+ { query: 'query($text: String!) { echo(text: $text) }',
variables: { 'text' => 'World' } }
]
@@ -23,8 +23,8 @@ describe 'Multiplexed queries' do
it 'returns error and data combinations' do
queries = [
- { query: 'query($text: String) { broken query }' },
- { query: 'query working($text: String) { echo(text: $text) }',
+ { query: 'query($text: String!) { broken query }' },
+ { query: 'query working($text: String!) { echo(text: $text) }',
variables: { 'text' => 'World' } }
]
diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb
index 521d6b88734..b7aa3f93451 100644
--- a/spec/requests/api/issues/get_project_issues_spec.rb
+++ b/spec/requests/api/issues/get_project_issues_spec.rb
@@ -446,6 +446,14 @@ describe API::Issues do
expect_paginated_array_response([closed_issue.id, confidential_issue.id, issue.id])
end
+ it 'exposes known attributes' do
+ get api("#{base_url}/issues", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response.last.keys).to include(*%w(id iid project_id title description))
+ expect(json_response.last).not_to have_key('subscribed')
+ end
+
context 'issues_statistics' do
context 'no state is treated as all state' do
let(:params) { {} }
diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb
index 35b3dd219f7..174b3214d13 100644
--- a/spec/requests/api/pipelines_spec.rb
+++ b/spec/requests/api/pipelines_spec.rb
@@ -17,6 +17,8 @@ describe API::Pipelines do
end
describe 'GET /projects/:id/pipelines ' do
+ it_behaves_like 'pipelines visibility table'
+
context 'authorized user' do
it 'returns project pipelines' do
get api("/projects/#{project.id}/pipelines", user)
@@ -401,6 +403,15 @@ describe API::Pipelines do
end
describe 'GET /projects/:id/pipelines/:pipeline_id' do
+ it_behaves_like 'pipelines visibility table' do
+ let(:pipelines_api_path) do
+ "/projects/#{project.id}/pipelines/#{pipeline.id}"
+ end
+
+ let(:api_response) { response_status == 200 ? response : json_response }
+ let(:response_200) { match_response_schema('public_api/v4/pipeline/detail') }
+ end
+
context 'authorized user' do
it 'exposes known attributes' do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index bba473f1c20..8b2c698fee1 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -108,6 +108,14 @@ describe JwtController do
end
end
end
+
+ it 'does not cause session based checks to be activated' do
+ expect(Gitlab::Session).not_to receive(:with_session)
+
+ get '/jwt/auth', params: parameters, headers: headers
+
+ expect(response).to have_gitlab_http_status(200)
+ end
end
context 'using invalid login' do
diff --git a/spec/rubocop/cop/gitlab/union_spec.rb b/spec/rubocop/cop/gitlab/union_spec.rb
index 5b06f30b25f..f0544fdb66e 100644
--- a/spec/rubocop/cop/gitlab/union_spec.rb
+++ b/spec/rubocop/cop/gitlab/union_spec.rb
@@ -16,10 +16,4 @@ describe RuboCop::Cop::Gitlab::Union do
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the `FromUnion` concern, instead of using `Gitlab::SQL::Union` directly
SOURCE
end
-
- it 'does not flag the use of Gitlab::SQL::Union in a spec' do
- allow(cop).to receive(:in_spec?).and_return(true)
-
- expect_no_offenses('Gitlab::SQL::Union.new([foo])')
- end
end
diff --git a/spec/rubocop/cop/migration/add_limit_to_string_columns_spec.rb b/spec/rubocop/cop/migration/add_limit_to_string_columns_spec.rb
new file mode 100644
index 00000000000..97a3ae8f2bc
--- /dev/null
+++ b/spec/rubocop/cop/migration/add_limit_to_string_columns_spec.rb
@@ -0,0 +1,268 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/add_limit_to_string_columns'
+
+describe RuboCop::Cop::Migration::AddLimitToStringColumns do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+
+ inspect_source(migration)
+ end
+
+ context 'when creating a table' do
+ context 'with string columns and limit' do
+ let(:migration) do
+ %q(
+ class CreateUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false, limit: 255
+ t.timestamps_with_timezone null: true
+ end
+ end
+ end
+ )
+ end
+
+ it 'register no offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+
+ context 'with limit in a different position' do
+ let(:migration) do
+ %q(
+ class CreateUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, limit: 255, null: false
+ t.timestamps_with_timezone null: true
+ end
+ end
+ end
+ )
+ end
+
+ it 'registers an offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'with string columns and no limit' do
+ let(:migration) do
+ %q(
+ class CreateUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false
+ t.timestamps_with_timezone null: true
+ end
+ end
+ end
+ )
+ end
+
+ it 'registers an offense' do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.first.message)
+ .to eq('String columns should have a limit constraint. 255 is suggested')
+ end
+ end
+
+ context 'with no string columns' do
+ let(:migration) do
+ %q(
+ class CreateMilestoneReleases < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ create_table :milestone_releases do |t|
+ t.integer :milestone_id
+ t.integer :release_id
+ end
+ end
+ end
+ )
+ end
+
+ it 'register no offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'when adding columns' do
+ context 'with string columns with limit' do
+ let(:migration) do
+ %q(
+ class AddEmailToUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column :users, :email, :string, limit: 255
+ end
+ end
+ )
+ end
+
+ it 'registers no offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+
+ context 'with limit in a different position' do
+ let(:migration) do
+ %q(
+ class AddEmailToUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column :users, :email, :string, limit: 255, default: 'example@email.com'
+ end
+ end
+ )
+ end
+
+ it 'registers no offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'with string columns with no limit' do
+ let(:migration) do
+ %q(
+ class AddEmailToUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column :users, :email, :string
+ end
+ end
+ )
+ end
+
+ it 'registers offense' do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.first.message)
+ .to eq('String columns should have a limit constraint. 255 is suggested')
+ end
+ end
+
+ context 'with no string columns' do
+ let(:migration) do
+ %q(
+ class AddEmailToUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column :users, :active, :boolean, default: false
+ end
+ end
+ )
+ end
+
+ it 'registers no offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'with add_column_with_default' do
+ context 'with a limit' do
+ let(:migration) do
+ %q(
+ class AddRuleTypeToApprovalMergeRequestRules < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column_with_default(:approval_merge_request_rules, :rule_type, :string, limit: 2, default: 1)
+ end
+ end
+ )
+ end
+
+ it 'registers no offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+
+ context 'without a limit' do
+ let(:migration) do
+ %q(
+ class AddRuleTypeToApprovalMergeRequestRules < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column_with_default(:approval_merge_request_rules, :rule_type, :string, default: 1)
+ end
+ end
+ )
+ end
+
+ it 'registers an offense' do
+ expect(cop.offenses.size).to eq(1)
+ end
+ end
+ end
+
+ context 'with methods' do
+ let(:migration) do
+ %q(
+ class AddEmailToUsers < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column_if_table_not_exists :users, :first_name, :string, limit: 255
+ search_namespace(user_name)
+ end
+
+ def add_column_if_not_exists(table, name, *args)
+ add_column(table, name, *args) unless column_exists?(table, name)
+ end
+
+ def search_namespace(username)
+ Uniquify.new.string(username) do |str|
+ query = "SELECT id FROM namespaces WHERE parent_id IS NULL AND path='#{str}' LIMIT 1"
+ connection.exec_query(query)
+ end
+ end
+ end
+ )
+ end
+
+ it 'registers no offense' do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'outside of migrations' do
+ let(:active_record_model) do
+ %q(
+ class User < ApplicationRecord
+ end
+ )
+ end
+
+ it 'registers no offense' do
+ inspect_source(active_record_model)
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/rspec/env_assignment_spec.rb b/spec/rubocop/cop/rspec/env_assignment_spec.rb
index 659633f6467..621afbad3ba 100644
--- a/spec/rubocop/cop/rspec/env_assignment_spec.rb
+++ b/spec/rubocop/cop/rspec/env_assignment_spec.rb
@@ -33,27 +33,13 @@ describe RuboCop::Cop::RSpec::EnvAssignment do
end
end
- context 'in a spec file' do
- before do
- allow(cop).to receive(:in_spec?).and_return(true)
- end
-
- context 'with a key using single quotes' do
- it_behaves_like 'an offensive ENV#[]= call', OFFENSE_CALL_SINGLE_QUOTES_KEY
- it_behaves_like 'an autocorrected ENV#[]= call', OFFENSE_CALL_SINGLE_QUOTES_KEY, %(stub_env('FOO', 'bar'))
- end
-
- context 'with a key using double quotes' do
- it_behaves_like 'an offensive ENV#[]= call', OFFENSE_CALL_DOUBLE_QUOTES_KEY
- it_behaves_like 'an autocorrected ENV#[]= call', OFFENSE_CALL_DOUBLE_QUOTES_KEY, %(stub_env("FOO", 'bar'))
- end
+ context 'with a key using single quotes' do
+ it_behaves_like 'an offensive ENV#[]= call', OFFENSE_CALL_SINGLE_QUOTES_KEY
+ it_behaves_like 'an autocorrected ENV#[]= call', OFFENSE_CALL_SINGLE_QUOTES_KEY, %(stub_env('FOO', 'bar'))
end
- context 'outside of a spec file' do
- it "does not register an offense for `#{OFFENSE_CALL_SINGLE_QUOTES_KEY}` in a non-spec file" do
- inspect_source(OFFENSE_CALL_SINGLE_QUOTES_KEY)
-
- expect(cop.offenses.size).to eq(0)
- end
+ context 'with a key using double quotes' do
+ it_behaves_like 'an offensive ENV#[]= call', OFFENSE_CALL_DOUBLE_QUOTES_KEY
+ it_behaves_like 'an autocorrected ENV#[]= call', OFFENSE_CALL_DOUBLE_QUOTES_KEY, %(stub_env("FOO", 'bar'))
end
end
diff --git a/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb b/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb
index 2763f2bda21..94324bc615d 100644
--- a/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb
+++ b/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb
@@ -8,8 +8,6 @@ require_relative '../../../../rubocop/cop/rspec/factories_in_migration_specs'
describe RuboCop::Cop::RSpec::FactoriesInMigrationSpecs do
include CopHelper
- let(:source_file) { 'spec/migrations/foo_spec.rb' }
-
subject(:cop) { described_class.new }
shared_examples 'an offensive factory call' do |namespace|
@@ -27,22 +25,6 @@ describe RuboCop::Cop::RSpec::FactoriesInMigrationSpecs do
end
end
- context 'in a migration spec file' do
- before do
- allow(cop).to receive(:in_migration_spec?).and_return(true)
- end
-
- it_behaves_like 'an offensive factory call', ''
- it_behaves_like 'an offensive factory call', 'FactoryBot.'
- end
-
- context 'outside of a migration spec file' do
- it "does not register an offense" do
- expect_no_offenses(<<-RUBY)
- describe 'foo' do
- let(:user) { create(:user) }
- end
- RUBY
- end
- end
+ it_behaves_like 'an offensive factory call', ''
+ it_behaves_like 'an offensive factory call', 'FactoryBot.'
end
diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb
index adb5219d691..ab06c1a1209 100644
--- a/spec/services/application_settings/update_service_spec.rb
+++ b/spec/services/application_settings/update_service_spec.rb
@@ -201,6 +201,24 @@ describe ApplicationSettings::UpdateService do
enable_external_authorization_service_check
end
+ it 'does not validate labels if external authorization gets disabled' do
+ expect_any_instance_of(described_class).not_to receive(:validate_classification_label)
+
+ described_class.new(application_settings, admin, { external_authorization_service_enabled: false }).execute
+ end
+
+ it 'does validate labels if external authorization gets enabled ' do
+ expect_any_instance_of(described_class).to receive(:validate_classification_label)
+
+ described_class.new(application_settings, admin, { external_authorization_service_enabled: true }).execute
+ end
+
+ it 'does validate labels if external authorization is left unchanged' do
+ expect_any_instance_of(described_class).to receive(:validate_classification_label)
+
+ described_class.new(application_settings, admin, { external_authorization_service_default_label: 'new-label' }).execute
+ end
+
it 'does not save the settings with an error if the service denies access' do
expect(::Gitlab::ExternalAuthorization)
.to receive(:access_allowed?).with(admin, 'new-label') { false }
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index ed48f4b1e44..699f2a98088 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe MergeRequests::CreateService do
+describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
include ProjectForksHelper
let(:project) { create(:project, :repository) }
@@ -285,6 +285,12 @@ describe MergeRequests::CreateService do
end
end
end
+
+ it 'increments the usage data counter of create event' do
+ counter = Gitlab::UsageDataCounters::MergeRequestCounter
+
+ expect { service.execute }.to change { counter.read(:create) }.by(1)
+ end
end
it_behaves_like 'new issuable record that supports quick actions' do
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index c8b2bf040e6..dec7898d8d2 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -30,6 +30,10 @@ module StubConfiguration
allow(Gitlab.config.gitlab).to receive_messages(to_settings(messages))
end
+ def stub_config(messages)
+ allow(Gitlab.config).to receive_messages(to_settings(messages))
+ end
+
def stub_default_url_options(host: "localhost", protocol: "http")
url_options = { host: host, protocol: protocol }
allow(Rails.application.routes).to receive(:default_url_options).and_return(url_options)
diff --git a/spec/support/shared_examples/cycle_analytics_stage_examples.rb b/spec/support/shared_examples/cycle_analytics_stage_examples.rb
new file mode 100644
index 00000000000..151f5325e84
--- /dev/null
+++ b/spec/support/shared_examples/cycle_analytics_stage_examples.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+shared_examples_for 'cycle analytics stage' do
+ let(:valid_params) do
+ {
+ name: 'My Stage',
+ parent: parent,
+ start_event_identifier: :merge_request_created,
+ end_event_identifier: :merge_request_merged
+ }
+ end
+
+ describe 'validation' do
+ it 'is valid' do
+ expect(described_class.new(valid_params)).to be_valid
+ end
+
+ it 'validates presence of parent' do
+ stage = described_class.new(valid_params.except(:parent))
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[parent_name]).to eq([{ error: :blank }])
+ end
+
+ it 'validates presence of start_event_identifier' do
+ stage = described_class.new(valid_params.except(:start_event_identifier))
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[:start_event_identifier]).to eq([{ error: :blank }])
+ end
+
+ it 'validates presence of end_event_identifier' do
+ stage = described_class.new(valid_params.except(:end_event_identifier))
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[:end_event_identifier]).to eq([{ error: :blank }])
+ end
+
+ it 'is invalid when end_event is not allowed for the given start_event' do
+ invalid_params = valid_params.merge(
+ start_event_identifier: :merge_request_merged,
+ end_event_identifier: :merge_request_created
+ )
+ stage = described_class.new(invalid_params)
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[:end_event]).to eq([{ error: :not_allowed_for_the_given_start_event }])
+ end
+ end
+
+ describe '#subject_model' do
+ it 'infers the model from the start event' do
+ stage = described_class.new(valid_params)
+
+ expect(stage.subject_model).to eq(MergeRequest)
+ end
+ end
+
+ describe '#start_event' do
+ it 'builds start_event object based on start_event_identifier' do
+ stage = described_class.new(start_event_identifier: 'merge_request_created')
+
+ expect(stage.start_event).to be_a_kind_of(Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated)
+ end
+ end
+
+ describe '#end_event' do
+ it 'builds end_event object based on end_event_identifier' do
+ stage = described_class.new(end_event_identifier: 'merge_request_merged')
+
+ expect(stage.end_event).to be_a_kind_of(Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
index a37b2392d52..bebc8509d53 100644
--- a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
@@ -89,5 +89,54 @@ shared_examples 'move quick action' do
it_behaves_like 'applies the commands to issues in both projects, target and source'
end
end
+
+ context 'when editing comments' do
+ let(:target_project) { create(:project, :public) }
+
+ before do
+ target_project.add_maintainer(user)
+
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ wait_for_all_requests
+ end
+
+ it 'moves the issue after quickcommand note was updated' do
+ # misspelled quick action
+ add_note("test note.\n/mvoe #{target_project.full_path}")
+
+ expect(issue.reload).not_to be_closed
+
+ edit_note("/mvoe #{target_project.full_path}", "test note.\n/move #{target_project.full_path}")
+ wait_for_all_requests
+
+ expect(page).to have_content 'test note.'
+ expect(issue.reload).to be_closed
+
+ visit project_issue_path(target_project, issue)
+ wait_for_all_requests
+
+ expect(page).to have_content 'Issues 1'
+ end
+
+ it 'deletes the note if it was updated to just contain a command' do
+ # missspelled quick action
+ add_note("test note.\n/mvoe #{target_project.full_path}")
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(issue.reload).not_to be_closed
+
+ edit_note("/mvoe #{target_project.full_path}", "/move #{target_project.full_path}")
+ wait_for_all_requests
+
+ expect(page).not_to have_content "/move #{target_project.full_path}"
+ expect(issue.reload).to be_closed
+
+ visit project_issue_path(target_project, issue)
+ wait_for_all_requests
+
+ expect(page).to have_content 'Issues 1'
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb b/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb
new file mode 100644
index 00000000000..dfd07176b1c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb
@@ -0,0 +1,235 @@
+# frozen_string_literal: true
+
+shared_examples 'pipelines visibility table' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:ci_user) { create(:user) }
+ let(:api_user) { user_role && ci_user }
+
+ let(:pipelines_api_path) do
+ "/projects/#{project.id}/pipelines"
+ end
+
+ let(:response_200) do
+ a_collection_containing_exactly(
+ a_hash_including('sha', 'ref', 'status', 'web_url', 'id' => pipeline.id)
+ )
+ end
+
+ let(:response_40x) do
+ a_hash_including('message')
+ end
+
+ let(:expected_response) do
+ if response_status == 200
+ response_200
+ else
+ response_40x
+ end
+ end
+
+ let(:api_response) { json_response }
+
+ let(:visibility_levels) do
+ {
+ private: Gitlab::VisibilityLevel::PRIVATE,
+ internal: Gitlab::VisibilityLevel::INTERNAL,
+ public: Gitlab::VisibilityLevel::PUBLIC
+ }
+ end
+
+ let(:builds_access_levels) do
+ {
+ enabled: ProjectFeature::ENABLED,
+ private: ProjectFeature::PRIVATE
+ }
+ end
+
+ let(:project_attributes) do
+ {
+ visibility_level: visibility_levels[visibility_level],
+ public_builds: public_builds
+ }
+ end
+
+ let(:project_feature_attributes) do
+ {
+ builds_access_level: builds_access_levels[builds_access_level]
+ }
+ end
+
+ where(:visibility_level, :builds_access_level, :public_builds, :is_admin, :user_role, :response_status) do
+ :private | :enabled | true | true | :non_member | 200
+ :private | :enabled | true | true | :guest | 200
+ :private | :enabled | true | true | :reporter | 200
+ :private | :enabled | true | true | :developer | 200
+ :private | :enabled | true | true | :maintainer | 200
+
+ :private | :enabled | true | false | nil | 404
+ :private | :enabled | true | false | :non_member | 404
+ :private | :enabled | true | false | :guest | 200
+ :private | :enabled | true | false | :reporter | 200
+ :private | :enabled | true | false | :developer | 200
+ :private | :enabled | true | false | :maintainer | 200
+
+ :private | :enabled | false | true | :non_member | 200
+ :private | :enabled | false | true | :guest | 200
+ :private | :enabled | false | true | :reporter | 200
+ :private | :enabled | false | true | :developer | 200
+ :private | :enabled | false | true | :maintainer | 200
+
+ :private | :enabled | false | false | nil | 404
+ :private | :enabled | false | false | :non_member | 404
+ :private | :enabled | false | false | :guest | 403
+ :private | :enabled | false | false | :reporter | 200
+ :private | :enabled | false | false | :developer | 200
+ :private | :enabled | false | false | :maintainer | 200
+
+ :private | :private | true | true | :non_member | 200
+ :private | :private | true | true | :guest | 200
+ :private | :private | true | true | :reporter | 200
+ :private | :private | true | true | :developer | 200
+ :private | :private | true | true | :maintainer | 200
+
+ :private | :private | true | false | nil | 404
+ :private | :private | true | false | :non_member | 404
+ :private | :private | true | false | :guest | 200
+ :private | :private | true | false | :reporter | 200
+ :private | :private | true | false | :developer | 200
+ :private | :private | true | false | :maintainer | 200
+
+ :private | :private | false | true | :non_member | 200
+ :private | :private | false | true | :guest | 200
+ :private | :private | false | true | :reporter | 200
+ :private | :private | false | true | :developer | 200
+ :private | :private | false | true | :maintainer | 200
+
+ :private | :private | false | false | nil | 404
+ :private | :private | false | false | :non_member | 404
+ :private | :private | false | false | :guest | 403
+ :private | :private | false | false | :reporter | 200
+ :private | :private | false | false | :developer | 200
+ :private | :private | false | false | :maintainer | 200
+
+ :internal | :enabled | true | true | :non_member | 200
+ :internal | :enabled | true | true | :guest | 200
+ :internal | :enabled | true | true | :reporter | 200
+ :internal | :enabled | true | true | :developer | 200
+ :internal | :enabled | true | true | :maintainer | 200
+
+ :internal | :enabled | true | false | nil | 404
+ :internal | :enabled | true | false | :non_member | 200
+ :internal | :enabled | true | false | :guest | 200
+ :internal | :enabled | true | false | :reporter | 200
+ :internal | :enabled | true | false | :developer | 200
+ :internal | :enabled | true | false | :maintainer | 200
+
+ :internal | :enabled | false | true | :non_member | 200
+ :internal | :enabled | false | true | :guest | 200
+ :internal | :enabled | false | true | :reporter | 200
+ :internal | :enabled | false | true | :developer | 200
+ :internal | :enabled | false | true | :maintainer | 200
+
+ :internal | :enabled | false | false | nil | 404
+ :internal | :enabled | false | false | :non_member | 403
+ :internal | :enabled | false | false | :guest | 403
+ :internal | :enabled | false | false | :reporter | 200
+ :internal | :enabled | false | false | :developer | 200
+ :internal | :enabled | false | false | :maintainer | 200
+
+ :internal | :private | true | true | :non_member | 200
+ :internal | :private | true | true | :guest | 200
+ :internal | :private | true | true | :reporter | 200
+ :internal | :private | true | true | :developer | 200
+ :internal | :private | true | true | :maintainer | 200
+
+ :internal | :private | true | false | nil | 404
+ :internal | :private | true | false | :non_member | 403
+ :internal | :private | true | false | :guest | 200
+ :internal | :private | true | false | :reporter | 200
+ :internal | :private | true | false | :developer | 200
+ :internal | :private | true | false | :maintainer | 200
+
+ :internal | :private | false | true | :non_member | 200
+ :internal | :private | false | true | :guest | 200
+ :internal | :private | false | true | :reporter | 200
+ :internal | :private | false | true | :developer | 200
+ :internal | :private | false | true | :maintainer | 200
+
+ :internal | :private | false | false | nil | 404
+ :internal | :private | false | false | :non_member | 403
+ :internal | :private | false | false | :guest | 403
+ :internal | :private | false | false | :reporter | 200
+ :internal | :private | false | false | :developer | 200
+ :internal | :private | false | false | :maintainer | 200
+
+ :public | :enabled | true | true | :non_member | 200
+ :public | :enabled | true | true | :guest | 200
+ :public | :enabled | true | true | :reporter | 200
+ :public | :enabled | true | true | :developer | 200
+ :public | :enabled | true | true | :maintainer | 200
+
+ :public | :enabled | true | false | nil | 200
+ :public | :enabled | true | false | :non_member | 200
+ :public | :enabled | true | false | :guest | 200
+ :public | :enabled | true | false | :reporter | 200
+ :public | :enabled | true | false | :developer | 200
+ :public | :enabled | true | false | :maintainer | 200
+
+ :public | :enabled | false | true | :non_member | 200
+ :public | :enabled | false | true | :guest | 200
+ :public | :enabled | false | true | :reporter | 200
+ :public | :enabled | false | true | :developer | 200
+ :public | :enabled | false | true | :maintainer | 200
+
+ :public | :enabled | false | false | nil | 403
+ :public | :enabled | false | false | :non_member | 403
+ :public | :enabled | false | false | :guest | 403
+ :public | :enabled | false | false | :reporter | 200
+ :public | :enabled | false | false | :developer | 200
+ :public | :enabled | false | false | :maintainer | 200
+
+ :public | :private | true | true | :non_member | 200
+ :public | :private | true | true | :guest | 200
+ :public | :private | true | true | :reporter | 200
+ :public | :private | true | true | :developer | 200
+ :public | :private | true | true | :maintainer | 200
+
+ :public | :private | true | false | nil | 403
+ :public | :private | true | false | :non_member | 403
+ :public | :private | true | false | :guest | 200
+ :public | :private | true | false | :reporter | 200
+ :public | :private | true | false | :developer | 200
+ :public | :private | true | false | :maintainer | 200
+
+ :public | :private | false | true | :non_member | 200
+ :public | :private | false | true | :guest | 200
+ :public | :private | false | true | :reporter | 200
+ :public | :private | false | true | :developer | 200
+ :public | :private | false | true | :maintainer | 200
+
+ :public | :private | false | false | nil | 403
+ :public | :private | false | false | :non_member | 403
+ :public | :private | false | false | :guest | 403
+ :public | :private | false | false | :reporter | 200
+ :public | :private | false | false | :developer | 200
+ :public | :private | false | false | :maintainer | 200
+ end
+
+ with_them do
+ before do
+ ci_user.update!(admin: is_admin) if user_role
+
+ project.update!(project_attributes)
+ project.project_feature.update!(project_feature_attributes)
+ project.add_role(ci_user, user_role) if user_role && user_role != :non_member
+
+ get api(pipelines_api_path, api_user)
+ end
+
+ it do
+ expect(response).to have_gitlab_http_status(response_status)
+ expect(api_response).to match(expected_response)
+ end
+ end
+end
diff --git a/spec/views/layouts/_head.html.haml_spec.rb b/spec/views/layouts/_head.html.haml_spec.rb
index 70cdc08b4b6..d7f24950e6f 100644
--- a/spec/views/layouts/_head.html.haml_spec.rb
+++ b/spec/views/layouts/_head.html.haml_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe 'layouts/_head' do
+ include StubConfiguration
+
before do
allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings)
end
@@ -87,6 +89,24 @@ describe 'layouts/_head' do
end
end
+ context 'when a Piwik config is set' do
+ let(:piwik_host) { 'piwik.example.com' }
+
+ before do
+ stub_config(extra: {
+ piwik_url: piwik_host,
+ piwik_site_id: 12345
+ })
+ end
+
+ it 'add a Piwik Javascript' do
+ render
+
+ expect(rendered).to match(/<script.*>.*var u="\/\/#{piwik_host}\/".*<\/script>/m)
+ expect(rendered).to match(%r(<noscript>.*<img src="//#{piwik_host}/piwik.php.*</noscript>))
+ end
+ end
+
def stub_helper_with_safe_string(method)
allow_any_instance_of(PageLayoutHelper).to receive(method)
.and_return(%q{foo" http-equiv="refresh}.html_safe)
diff --git a/yarn.lock b/yarn.lock
index 4489b10815a..712cdace0d7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -998,15 +998,15 @@
dependencies:
vue-eslint-parser "^6.0.4"
-"@gitlab/svgs@^1.68.0":
- version "1.68.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.68.0.tgz#d631bd84ea7907592240d8417e82ba66d6a54c0c"
- integrity sha512-3JmIq0bHg4InjLooM+kQFPfg3d7B1Pye67pN9+12kZXIa0nRGuwKEq3WSbcS+ACdg5jcVPNPYqStItEO4teHdw==
+"@gitlab/svgs@^1.70.0":
+ version "1.70.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.70.0.tgz#bdae478148c15d955fc06e69fd5d5ecae8298943"
+ integrity sha512-0uV9fgTwe17Fyy0hTcrsGX2jJuCrz3uRIe8yffuqc6pbQrSfYJyN66mfCCB45wq8lKTgOB5q0qcUyJx3RQEcKg==
-"@gitlab/ui@5.18.0":
- version "5.18.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.18.0.tgz#f7f93ad41673f5ae081cd2246dda5456d3c956a2"
- integrity sha512-umB7JCKVDZOajed0N563JBYSpiyK+VDL2eCdkinW+twWhMct8onoW4CLTpkgBi6Z9Y1Bq47aqnFtGf+1IKNIGw==
+"@gitlab/ui@5.19.0":
+ version "5.19.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.19.0.tgz#ef5431e0e91eb4009a30edcf49a40716cc2570d9"
+ integrity sha512-gCeTymtVzzO2uOWZGIweLM5JcHq3TN1QwP61CXw7b9Lp5A2MysRb8upehtR5d4JLOf/GQg8rHQB26uRvUc+AXQ==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"
@@ -1021,6 +1021,11 @@
vue "^2.6.10"
vue-loader "^15.4.2"
+"@gitlab/visual-review-tools@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.0.0.tgz#6012e0a19797c1f5dad34ccf4dacdaf38e400a73"
+ integrity sha512-xMvz9IwrXisQ1MH+Tj6lfbQcQSiQy88nTPuQV6OTLBGuV+vIQeVwXeIkQeTKuSpd0GqZvigPdRqxyQCa3blpIg==
+
"@gitlab/vue-toasted@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@gitlab/vue-toasted/-/vue-toasted-1.2.1.tgz#f407b5aa710863e5b7f021f4a1f66160331ab263"