summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml5
-rw-r--r--.gitlab/issue_templates/Documentation.md2
-rw-r--r--.gitlab/merge_request_templates/Change documentation location.md2
-rw-r--r--.mdlrc3
-rw-r--r--.mdlrc.style22
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock87
-rw-r--r--README.md2
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_mermaid.js3
-rw-r--r--app/assets/javascripts/boards/components/modal/footer.vue2
-rw-r--r--app/assets/javascripts/boards/services/board_service.js16
-rw-r--r--app/assets/javascripts/boards/stores/boards_store.js38
-rw-r--r--app/assets/javascripts/create_merge_request_dropdown.js2
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js10
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue19
-rw-r--r--app/assets/javascripts/issue_show/components/locked_warning.vue21
-rw-r--r--app/assets/javascripts/notes/components/note_actions/reply_button.vue2
-rw-r--r--app/assets/javascripts/notes/stores/actions.js4
-rw-r--r--app/assets/javascripts/registry/components/app.vue51
-rw-r--r--app/assets/javascripts/registry/components/svg_message.vue6
-rw-r--r--app/assets/javascripts/related_merge_requests/components/related_merge_requests.vue2
-rw-r--r--app/assets/javascripts/reports/components/issue_status_icon.vue2
-rw-r--r--app/assets/javascripts/reports/components/report_item.vue9
-rw-r--r--app/assets/javascripts/reports/components/report_section.vue4
-rw-r--r--app/assets/javascripts/reports/components/summary_row.vue14
-rw-r--r--app/assets/javascripts/repository/components/breadcrumbs.vue186
-rw-r--r--app/assets/javascripts/repository/index.js50
-rw-r--r--app/assets/javascripts/repository/queries/getPermissions.query.graphql9
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue4
-rw-r--r--app/assets/stylesheets/components/avatar.scss5
-rw-r--r--app/assets/stylesheets/components/popover.scss1
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/asciidoctor.scss27
-rw-r--r--app/assets/stylesheets/framework/filters.scss53
-rw-r--r--app/assets/stylesheets/framework/icons.scss3
-rw-r--r--app/assets/stylesheets/framework/modal.scss30
-rw-r--r--app/assets/stylesheets/framework/panels.scss1
-rw-r--r--app/assets/stylesheets/framework/typography.scss65
-rw-r--r--app/assets/stylesheets/pages/commits.scss2
-rw-r--r--app/assets/stylesheets/pages/container_registry.scss4
-rw-r--r--app/assets/stylesheets/pages/diff.scss2
-rw-r--r--app/assets/stylesheets/pages/help.scss6
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss27
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss4
-rw-r--r--app/assets/stylesheets/pages/projects.scss2
-rw-r--r--app/assets/stylesheets/pages/reports.scss9
-rw-r--r--app/controllers/admin/application_settings_controller.rb12
-rw-r--r--app/controllers/boards/issues_controller.rb7
-rw-r--r--app/controllers/concerns/requires_whitelisted_monitoring_client.rb2
-rw-r--r--app/controllers/groups_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb16
-rw-r--r--app/graphql/mutations/award_emojis/base.rb2
-rw-r--r--app/graphql/mutations/base_mutation.rb1
-rw-r--r--app/graphql/mutations/merge_requests/base.rb1
-rw-r--r--app/graphql/mutations/notes/base.rb2
-rw-r--r--app/helpers/blob_helper.rb11
-rw-r--r--app/helpers/boards_helper.rb6
-rw-r--r--app/helpers/icons_helper.rb21
-rw-r--r--app/helpers/sorting_helper.rb83
-rw-r--r--app/helpers/tree_helper.rb32
-rw-r--r--app/helpers/visibility_level_helper.rb22
-rw-r--r--app/models/ci/build.rb2
-rw-r--r--app/models/ci/pipeline.rb2
-rw-r--r--app/models/ci/pipeline_schedule.rb3
-rw-r--r--app/models/ci/trigger.rb11
-rw-r--r--app/models/clusters/applications/runner.rb15
-rw-r--r--app/models/clusters/concerns/application_core.rb10
-rw-r--r--app/models/clusters/concerns/application_status.rb24
-rw-r--r--app/models/concerns/has_status.rb66
-rw-r--r--app/models/concerns/relative_positioning.rb2
-rw-r--r--app/models/concerns/routable.rb2
-rw-r--r--app/models/concerns/stepable.rb35
-rw-r--r--app/models/concerns/token_authenticatable.rb2
-rw-r--r--app/models/email.rb3
-rw-r--r--app/models/issue.rb3
-rw-r--r--app/models/merge_request.rb11
-rw-r--r--app/models/merge_requests_closing_issues.rb2
-rw-r--r--app/models/namespace.rb11
-rw-r--r--app/models/pages_domain.rb10
-rw-r--r--app/models/project.rb17
-rw-r--r--app/models/project_services/ci_service.rb2
-rw-r--r--app/models/project_services/jira_service.rb2
-rw-r--r--app/models/project_services/slash_commands_service.rb2
-rw-r--r--app/models/user.rb12
-rw-r--r--app/policies/ci/trigger_policy.rb2
-rw-r--r--app/policies/clusters/instance_policy.rb7
-rw-r--r--app/policies/concerns/clusterable_actions.rb14
-rw-r--r--app/policies/group_policy.rb7
-rw-r--r--app/policies/project_policy.rb6
-rw-r--r--app/presenters/clusterable_presenter.rb14
-rw-r--r--app/serializers/current_board_entity.rb6
-rw-r--r--app/serializers/current_board_serializer.rb5
-rw-r--r--app/services/audit_event_service.rb6
-rw-r--r--app/services/boards/issues/move_service.rb39
-rw-r--r--app/services/ci/process_pipeline_service.rb4
-rw-r--r--app/services/clusters/applications/check_uninstall_progress_service.rb1
-rw-r--r--app/services/clusters/create_service.rb17
-rw-r--r--app/services/groups/create_service.rb3
-rw-r--r--app/services/issuable/clone/content_rewriter.rb6
-rw-r--r--app/services/self_monitoring/project/create_service.rb132
-rw-r--r--app/validators/namespace_name_validator.rb12
-rw-r--r--app/views/admin/application_settings/_pages.html.haml35
-rw-r--r--app/views/devise/sessions/_new_base.html.haml6
-rw-r--r--app/views/devise/shared/_tabs_normal.html.haml2
-rw-r--r--app/views/help/index.html.haml2
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/devise.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml4
-rw-r--r--app/views/layouts/header/_new_dropdown.haml2
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml4
-rw-r--r--app/views/notify/pages_domain_disabled_email.html.haml2
-rw-r--r--app/views/notify/pages_domain_disabled_email.text.haml2
-rw-r--r--app/views/notify/pages_domain_enabled_email.html.haml2
-rw-r--r--app/views/notify/pages_domain_enabled_email.text.haml2
-rw-r--r--app/views/notify/pages_domain_verification_failed_email.html.haml2
-rw-r--r--app/views/notify/pages_domain_verification_failed_email.text.haml2
-rw-r--r--app/views/notify/pages_domain_verification_succeeded_email.html.haml2
-rw-r--r--app/views/notify/pages_domain_verification_succeeded_email.text.haml2
-rw-r--r--app/views/projects/_files.html.haml3
-rw-r--r--app/views/projects/_new_project_fields.html.haml4
-rw-r--r--app/views/projects/issues/import_csv/_modal.html.haml2
-rw-r--r--app/views/projects/new.html.haml8
-rw-r--r--app/views/projects/pages_domains/_form.html.haml2
-rw-r--r--app/views/projects/pages_domains/_helper_text.html.haml8
-rw-r--r--app/views/projects/pages_domains/show.html.haml2
-rw-r--r--app/views/projects/project_templates/_built_in_templates.html.haml4
-rw-r--r--app/views/projects/tree/_tree_header.html.haml2
-rw-r--r--app/views/projects/triggers/_content.html.haml17
-rw-r--r--app/views/projects/triggers/_trigger.html.haml7
-rw-r--r--app/views/shared/_visibility_radios.html.haml18
-rw-r--r--app/views/shared/boards/_show.html.haml3
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml6
-rw-r--r--app/workers/pages_domain_ssl_renewal_cron_worker.rb4
-rw-r--r--app/workers/pages_domain_ssl_renewal_worker.rb2
-rwxr-xr-xbin/bundle2
-rwxr-xr-xbin/setup31
-rwxr-xr-xbin/update6
-rwxr-xr-xbin/yarn11
-rw-r--r--changelogs/unreleased/51952-redirect-to-webide-in-fork.yml5
-rw-r--r--changelogs/unreleased/55623-group-cluster-apis.yml5
-rw-r--r--changelogs/unreleased/57538-normalize-users-private-profile-field.yml5
-rw-r--r--changelogs/unreleased/60666-kubernetes-applications-uninstall-runner.yml5
-rw-r--r--changelogs/unreleased/61342-commit-search-result-doesn-t-pass-wcag-color-audit.yml5
-rw-r--r--changelogs/unreleased/61613-spacing-mr-widgets.yml5
-rw-r--r--changelogs/unreleased/63298-prevent-excessive-sanitization-asciidoc.yml5
-rw-r--r--changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml5
-rw-r--r--changelogs/unreleased/64249-align-container-registry-empty-state-with-design-guidelines.yml5
-rw-r--r--changelogs/unreleased/64407-vfazio-quirk-omniauth-strategies-openidconnect.yml5
-rw-r--r--changelogs/unreleased/64416-lodash-4-6-2-for-prototype-pollution.yml5
-rw-r--r--changelogs/unreleased/bjk-fix_prom_example.yml5
-rw-r--r--changelogs/unreleased/button-bug-fixes.yml5
-rw-r--r--changelogs/unreleased/bvl-rename-routes-after-user-rename.yml5
-rw-r--r--changelogs/unreleased/fe-delete-old-boardservice-on-component-modal-footer.yml6
-rw-r--r--changelogs/unreleased/fix-broken-vue-i18n-strings.yml5
-rw-r--r--changelogs/unreleased/fix-comment-race-condition.yml5
-rw-r--r--changelogs/unreleased/georgekoltsov-63955-fix-import-with-source-branch-deleted.yml5
-rw-r--r--changelogs/unreleased/hide-restricted-visibility-radio.yml5
-rw-r--r--changelogs/unreleased/id-clean-up-mr-assignees.yml5
-rw-r--r--changelogs/unreleased/jc-remove-catfile-flag.yml5
-rw-r--r--changelogs/unreleased/mh-boards-filter-bar.yml5
-rw-r--r--changelogs/unreleased/mh-mermaid-linebreaks.yml5
-rw-r--r--changelogs/unreleased/remove-auto-ssl-ff.yml6
-rw-r--r--changelogs/unreleased/remove-support-for-legacy-pipeline-triggers.yml5
-rw-r--r--changelogs/unreleased/sh-audit-event-json-log-format-from-and-to.yml5
-rw-r--r--changelogs/unreleased/sh-fix-httpclient-ssl.yml5
-rw-r--r--changelogs/unreleased/update-pages-to-1-7-0.yml5
-rw-r--r--changelogs/unreleased/z-index-fix-for-diff-file-dropdown.yml5
-rw-r--r--config/application.rb26
-rw-r--r--config/environments/development.rb1
-rw-r--r--config/environments/test.rb3
-rw-r--r--config/gitlab.yml.example13
-rw-r--r--config/initializers/active_record_data_types.rb4
-rw-r--r--config/initializers/active_record_preloader.rb17
-rw-r--r--config/initializers/active_record_query_cache.rb3
-rw-r--r--config/initializers/active_record_verbose_query_logs.rb56
-rw-r--r--config/initializers/ar_speed_up_migration_checking.rb17
-rw-r--r--config/initializers/config_initializers_active_record_locking.rb9
-rw-r--r--config/initializers/httpclient_patch.rb18
-rw-r--r--config/initializers/lograge.rb2
-rw-r--r--config/initializers/mysql_ignore_postgresql_options.rb7
-rw-r--r--config/initializers/postgresql_cte.rb4
-rw-r--r--config/initializers/zz_metrics.rb2
-rw-r--r--config/routes.rb6
-rw-r--r--config/webpack.config.js6
-rw-r--r--danger/commit_messages/Dangerfile23
-rw-r--r--db/migrate/20190620105427_change_null_private_profile_to_false.rb33
-rw-r--r--db/post_migrate/20190628191740_schedule_fixing_names_of_user_namespaces.rb48
-rw-r--r--db/post_migrate/20190702173936_populate_remaining_merge_request_assignees.rb20
-rw-r--r--db/schema.rb98
-rw-r--r--doc/README.md4
-rw-r--r--doc/administration/auth/README.md37
-rw-r--r--doc/administration/auth/authentiq.md85
-rw-r--r--doc/administration/auth/crowd.md77
-rw-r--r--doc/administration/auth/google_secure_ldap.md22
-rw-r--r--doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md20
-rw-r--r--doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md22
-rw-r--r--doc/administration/auth/jwt.md134
-rw-r--r--doc/administration/auth/ldap-ee.md260
-rw-r--r--doc/administration/auth/ldap.md92
-rw-r--r--doc/administration/auth/oidc.md159
-rw-r--r--doc/administration/auth/okta.md232
-rw-r--r--doc/administration/auth/smartcard.md86
-rw-r--r--doc/administration/container_registry.md7
-rw-r--r--doc/administration/dependency_proxy.md1
-rw-r--r--doc/administration/geo/disaster_recovery/bring_primary_back.md2
-rw-r--r--doc/administration/geo/disaster_recovery/planned_failover.md2
-rw-r--r--doc/administration/geo/replication/database.md34
-rw-r--r--doc/administration/geo/replication/external_database.md1
-rw-r--r--doc/administration/geo/replication/remove_geo_node.md12
-rw-r--r--doc/administration/geo/replication/updating_the_geo_nodes.md10
-rw-r--r--doc/administration/high_availability/README.md13
-rw-r--r--doc/administration/high_availability/alpha_database.md3
-rw-r--r--doc/administration/high_availability/consul.md72
-rw-r--r--doc/administration/high_availability/database.md409
-rw-r--r--doc/administration/high_availability/gitaly.md16
-rw-r--r--doc/administration/high_availability/gitlab.md136
-rw-r--r--doc/administration/high_availability/load_balancer.md16
-rw-r--r--doc/administration/high_availability/monitoring_node.md94
-rw-r--r--doc/administration/high_availability/nfs.md50
-rw-r--r--doc/administration/high_availability/nfs_host_client_setup.md16
-rw-r--r--doc/administration/high_availability/pgbouncer.md85
-rw-r--r--doc/administration/high_availability/redis.md409
-rw-r--r--doc/administration/high_availability/redis_source.md311
-rw-r--r--doc/administration/housekeeping.md3
-rw-r--r--doc/administration/integration/plantuml.md49
-rw-r--r--doc/administration/integration/terminal.md4
-rw-r--r--doc/administration/job_artifacts.md18
-rw-r--r--doc/administration/monitoring/performance/gitlab_configuration.md6
-rw-r--r--doc/administration/monitoring/performance/performance_bar.md4
-rw-r--r--doc/administration/monitoring/prometheus/index.md54
-rw-r--r--doc/administration/operations/filesystem_benchmarking.md6
-rw-r--r--doc/administration/pages/index.md2
-rw-r--r--doc/administration/pseudonymizer.md4
-rw-r--r--doc/administration/raketasks/geo.md4
-rw-r--r--doc/administration/raketasks/maintenance.md19
-rw-r--r--doc/administration/raketasks/project_import_export.md16
-rw-r--r--doc/administration/raketasks/storage.md29
-rw-r--r--doc/administration/repository_storage_paths.md4
-rw-r--r--doc/administration/uploads.md88
-rw-r--r--doc/api/README.md5
-rw-r--r--doc/api/commits.md1
-rw-r--r--doc/api/dependencies.md50
-rw-r--r--doc/api/discussions.md230
-rw-r--r--doc/api/group_clusters.md280
-rw-r--r--doc/api/groups.md2
-rw-r--r--doc/api/issues.md1
-rw-r--r--doc/api/jobs.md14
-rw-r--r--doc/api/merge_requests.md8
-rw-r--r--doc/api/protected_tags.md1
-rw-r--r--doc/api/releases/img/upcoming_release_v12_1.pngbin0 -> 22635 bytes
-rw-r--r--doc/api/releases/index.md18
-rw-r--r--doc/api/repositories.md24
-rw-r--r--doc/api/repository_submodules.md2
-rw-r--r--doc/api/system_hooks.md8
-rw-r--r--doc/api/tags.md1
-rw-r--r--doc/api/users.md10
-rw-r--r--doc/ci/docker/using_docker_images.md65
-rw-r--r--doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md4
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/index.md1
-rw-r--r--doc/ci/examples/php.md2
-rw-r--r--doc/ci/git_submodules.md14
-rw-r--r--doc/ci/interactive_web_terminal/index.md3
-rw-r--r--doc/ci/services/postgres.md2
-rw-r--r--doc/ci/yaml/README.md71
-rw-r--r--doc/development/api_graphql_styleguide.md8
-rw-r--r--doc/development/architecture.md2
-rw-r--r--doc/development/changelog.md1
-rw-r--r--doc/development/code_review.md6
-rw-r--r--doc/development/contributing/issue_workflow.md88
-rw-r--r--doc/development/contributing/merge_request_workflow.md8
-rw-r--r--doc/development/documentation/index.md10
-rw-r--r--doc/development/documentation/site_architecture/global_nav.md12
-rw-r--r--doc/development/documentation/site_architecture/index.md8
-rw-r--r--doc/development/documentation/structure.md4
-rw-r--r--doc/development/documentation/styleguide.md6
-rw-r--r--doc/development/documentation/workflow.md2
-rw-r--r--doc/development/fe_guide/design_patterns.md3
-rw-r--r--doc/development/fe_guide/droplab/droplab.md8
-rw-r--r--doc/development/fe_guide/droplab/plugins/ajax.md19
-rw-r--r--doc/development/fe_guide/droplab/plugins/filter.md37
-rw-r--r--doc/development/fe_guide/droplab/plugins/input_setter.md53
-rw-r--r--doc/development/fe_guide/event_tracking.md2
-rw-r--r--doc/development/fe_guide/index.md10
-rw-r--r--doc/development/fe_guide/vue.md1
-rw-r--r--doc/development/gitaly.md19
-rw-r--r--doc/development/i18n/proofreader.md29
-rw-r--r--doc/development/integrations/jira_connect.md2
-rw-r--r--doc/development/new_fe_guide/index.md1
-rw-r--r--doc/development/new_fe_guide/style/prettier.md3
-rw-r--r--doc/development/performance.md1
-rw-r--r--doc/development/testing_guide/end_to_end/index.md2
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md2
-rw-r--r--doc/development/testing_guide/end_to_end/style_guide.md13
-rw-r--r--doc/development/testing_guide/frontend_testing.md8
-rw-r--r--doc/development/testing_guide/index.md18
-rw-r--r--doc/gitlab-basics/command-line-commands.md1
-rw-r--r--doc/install/aws/index.md2
-rw-r--r--doc/integration/elasticsearch.md6
-rw-r--r--doc/integration/oauth_provider.md12
-rw-r--r--doc/migrate_ci_to_ce/README.md14
-rw-r--r--doc/pages/getting_started_part_three.md4
-rw-r--r--doc/raketasks/backup_restore.md13
-rw-r--r--doc/raketasks/import.md2
-rw-r--r--doc/security/information_exclusivity.md1
-rw-r--r--doc/security/password_length_limits.md30
-rw-r--r--doc/security/rack_attack.md77
-rw-r--r--doc/security/reset_root_password.md1
-rw-r--r--doc/security/ssh_keys_restrictions.md1
-rw-r--r--doc/security/two_factor_authentication.md7
-rw-r--r--doc/security/unlock_user.md47
-rw-r--r--doc/security/user_email_confirmation.md1
-rw-r--r--doc/security/user_file_uploads.md3
-rw-r--r--doc/security/webhooks.md1
-rw-r--r--doc/ssh/README.md81
-rw-r--r--doc/system_hooks/system_hooks.md1
-rw-r--r--doc/topics/autodevops/index.md13
-rw-r--r--doc/university/training/topics/env_setup.md2
-rw-r--r--doc/user/admin_area/geo_nodes.md4
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md2
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md22
-rw-r--r--doc/user/admin_area/settings/img/admin_required_pipeline.pngbin0 -> 64548 bytes
-rw-r--r--doc/user/admin_area/settings/sign_up_restrictions.md22
-rw-r--r--doc/user/application_security/container_scanning/index.md133
-rw-r--r--doc/user/application_security/dast/index.md127
-rw-r--r--doc/user/application_security/dependency_scanning/index.md118
-rw-r--r--doc/user/application_security/license_management/index.md120
-rw-r--r--doc/user/application_security/sast/index.md110
-rw-r--r--doc/user/asciidoc.md9
-rw-r--r--doc/user/award_emojis.md2
-rw-r--r--doc/user/clusters/applications.md1
-rw-r--r--doc/user/discussions/img/automatically_resolve_outdated_discussions.pngbin38001 -> 57642 bytes
-rw-r--r--doc/user/discussions/img/btn_new_issue_for_all_discussions.pngbin9555 -> 0 bytes
-rw-r--r--doc/user/discussions/img/btn_new_issue_for_all_threads.pngbin0 -> 19431 bytes
-rw-r--r--doc/user/discussions/img/commit_comment_mr_context.pngbin25854 -> 365956 bytes
-rw-r--r--doc/user/discussions/img/commit_comment_mr_discussions_tab.pngbin15139 -> 276385 bytes
-rw-r--r--doc/user/discussions/img/discussion_comment.pngbin37351 -> 60561 bytes
-rw-r--r--doc/user/discussions/img/discussion_view.pngbin73807 -> 0 bytes
-rw-r--r--doc/user/discussions/img/image_resolved_discussion.pngbin48234 -> 199539 bytes
-rw-r--r--doc/user/discussions/img/merge_request_commits_tab.pngbin12792 -> 169010 bytes
-rw-r--r--doc/user/discussions/img/mr_review_resolve.pngbin21941 -> 247868 bytes
-rw-r--r--doc/user/discussions/img/mr_review_resolve2.pngbin9430 -> 232589 bytes
-rw-r--r--doc/user/discussions/img/mr_review_second_comment.pngbin11188 -> 183733 bytes
-rw-r--r--doc/user/discussions/img/mr_review_second_comment_added.pngbin9673 -> 161924 bytes
-rw-r--r--doc/user/discussions/img/mr_review_start.pngbin23491 -> 274186 bytes
-rw-r--r--doc/user/discussions/img/mr_review_unresolve.pngbin11302 -> 298513 bytes
-rw-r--r--doc/user/discussions/img/new_issue_for_thread.pngbin0 -> 21119 bytes
-rw-r--r--doc/user/discussions/img/onion_skin_view.pngbin45053 -> 95809 bytes
-rw-r--r--doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.pngbin0 -> 53804 bytes
-rw-r--r--doc/user/discussions/img/pending_review_comment.pngbin8793 -> 247865 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_thread.pngbin0 -> 119608 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_threads.pngbin0 -> 131506 bytes
-rw-r--r--doc/user/discussions/img/resolve_comment_button.pngbin4713 -> 11680 bytes
-rw-r--r--doc/user/discussions/img/resolve_thread_button.pngbin0 -> 34562 bytes
-rw-r--r--doc/user/discussions/img/resolve_thread_issue_notice.pngbin0 -> 44429 bytes
-rw-r--r--doc/user/discussions/img/resolve_thread_open_issue.pngbin0 -> 57089 bytes
-rw-r--r--doc/user/discussions/img/review_comment_quickactions.pngbin12392 -> 270228 bytes
-rw-r--r--doc/user/discussions/img/review_preview.pngbin19769 -> 84789 bytes
-rw-r--r--doc/user/discussions/img/swipe_view.pngbin16483 -> 71076 bytes
-rw-r--r--doc/user/discussions/img/thread_view.pngbin0 -> 556169 bytes
-rw-r--r--doc/user/discussions/img/threads_resolved.pngbin0 -> 12667 bytes
-rw-r--r--doc/user/discussions/img/two_up_view.pngbin61759 -> 118688 bytes
-rw-r--r--doc/user/discussions/index.md218
-rw-r--r--doc/user/group/custom_project_templates.md2
-rw-r--r--doc/user/group/epics/index.md4
-rw-r--r--doc/user/group/saml_sso/scim_setup.md46
-rw-r--r--doc/user/index.md6
-rw-r--r--doc/user/markdown.md12
-rw-r--r--doc/user/permissions.md4
-rw-r--r--doc/user/profile/account/two_factor_authentication.md46
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/index.md174
-rw-r--r--doc/user/project/clusters/index.md222
-rw-r--r--doc/user/project/clusters/runbooks/index.md61
-rw-r--r--doc/user/project/clusters/serverless/index.md689
-rw-r--r--doc/user/project/code_owners.md4
-rw-r--r--doc/user/project/container_registry.md8
-rw-r--r--doc/user/project/deploy_boards.md14
-rw-r--r--doc/user/project/deploy_tokens/index.md6
-rw-r--r--doc/user/project/import/bitbucket_server.md5
-rw-r--r--doc/user/project/import/index.md4
-rw-r--r--doc/user/project/index.md2
-rw-r--r--doc/user/project/integrations/custom_issue_tracker.md4
-rw-r--r--doc/user/project/integrations/gitlab_slack_application.md2
-rw-r--r--doc/user/project/integrations/jira_server_configuration.md26
-rw-r--r--doc/user/project/integrations/project_services.md8
-rw-r--r--doc/user/project/integrations/prometheus.md129
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md24
-rw-r--r--doc/user/project/issues/crosslinking_issues.md2
-rw-r--r--doc/user/project/issues/csv_export.md2
-rw-r--r--doc/user/project/issues/issue_data_and_actions.md26
-rw-r--r--doc/user/project/members/index.md22
-rw-r--r--doc/user/project/merge_requests/index.md10
-rw-r--r--doc/user/project/merge_requests/merge_request_approvals.md2
-rw-r--r--doc/user/project/merge_requests/merge_when_pipeline_succeeds.md2
-rw-r--r--doc/user/project/merge_requests/work_in_progress_merge_requests.md6
-rw-r--r--doc/user/project/milestones/index.md4
-rw-r--r--doc/user/project/new_ci_build_permissions_model.md4
-rw-r--r--doc/user/project/packages/maven_repository.md96
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md95
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/img/add_certificate_to_pages.png (renamed from doc/user/project/pages/img/add_certificate_to_pages.png)bin14608 -> 14608 bytes
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/img/dns_add_new_a_record_example_updated_2018.png (renamed from doc/user/project/pages/img/dns_add_new_a_record_example_updated_2018.png)bin3701 -> 3701 bytes
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/img/dns_cname_record_example.png (renamed from doc/user/project/pages/img/dns_cname_record_example.png)bin4983 -> 4983 bytes
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.pngbin0 -> 194433 bytes
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.pngbin0 -> 191712 bytes
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md257
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md75
-rw-r--r--doc/user/project/pages/getting_started_part_three.md315
-rw-r--r--doc/user/project/pages/getting_started_part_two.md4
-rw-r--r--doc/user/project/pages/img/pages_project_templates_v11_8.png (renamed from doc/user/project/pages/img/pages_project_templates_11-8.png)bin69702 -> 69702 bytes
-rw-r--r--doc/user/project/pages/img/verify_your_domain.pngbin12082 -> 0 bytes
-rw-r--r--doc/user/project/pages/index.md8
-rw-r--r--doc/user/project/pages/lets_encrypt_for_gitlab_pages.md148
-rw-r--r--doc/user/project/pipelines/job_artifacts.md12
-rw-r--r--doc/user/project/pipelines/settings.md4
-rw-r--r--doc/user/project/quick_actions.md28
-rw-r--r--doc/user/project/repository/gpg_signed_commits/index.md155
-rw-r--r--doc/user/project/repository/reducing_the_repo_size_using_git.md82
-rw-r--r--doc/user/project/repository/web_editor.md12
-rw-r--r--doc/user/project/service_desk.md45
-rw-r--r--doc/user/project/settings/import_export.md68
-rw-r--r--doc/user/project/settings/index.md4
-rw-r--r--doc/user/project/web_ide/index.md1
-rw-r--r--doc/workflow/README.md2
-rw-r--r--doc/workflow/file_finder.md4
-rw-r--r--doc/workflow/issue_weight.md2
-rw-r--r--doc/workflow/lfs/lfs_administration.md60
-rw-r--r--doc/workflow/lfs/manage_large_binaries_with_git_lfs.md2
-rw-r--r--doc/workflow/notifications.md2
-rw-r--r--doc/workflow/todos.md16
-rw-r--r--lib/api/api.rb4
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/group_clusters.rb140
-rw-r--r--lib/api/helpers/pagination.rb4
-rw-r--r--lib/api/helpers/runner.rb3
-rw-r--r--lib/api/project_clusters.rb2
-rw-r--r--lib/api/releases.rb2
-rw-r--r--lib/api/users.rb2
-rw-r--r--lib/banzai/filter/ascii_doc_sanitization_filter.rb88
-rw-r--r--lib/banzai/filter/base_sanitization_filter.rb96
-rw-r--r--lib/banzai/filter/reference_redactor_filter.rb (renamed from lib/banzai/filter/redactor_filter.rb)4
-rw-r--r--lib/banzai/filter/sanitization_filter.rb82
-rw-r--r--lib/banzai/object_renderer.rb2
-rw-r--r--lib/banzai/pipeline/ascii_doc_pipeline.rb2
-rw-r--r--lib/banzai/pipeline/post_process_pipeline.rb2
-rw-r--r--lib/banzai/reference_redactor.rb (renamed from lib/banzai/redactor.rb)2
-rw-r--r--lib/banzai/renderer.rb2
-rw-r--r--lib/feature/gitaly.rb6
-rw-r--r--lib/gitlab/asciidoc.rb1
-rw-r--r--lib/gitlab/background_migration/fix_user_namespace_names.rb68
-rw-r--r--lib/gitlab/background_migration/fix_user_project_route_names.rb38
-rw-r--r--lib/gitlab/background_migration/migrate_null_private_profile_to_false.rb17
-rw-r--r--lib/gitlab/background_migration/populate_merge_request_assignees_table.rb8
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb6
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/abilities.rb4
-rw-r--r--lib/gitlab/ci/pipeline/expression/lexeme/pattern.rb11
-rw-r--r--lib/gitlab/ci/pipeline/expression/lexer.rb17
-rw-r--r--lib/gitlab/ci/pipeline/expression/parser.rb39
-rw-r--r--lib/gitlab/current_settings.rb2
-rw-r--r--lib/gitlab/database.rb29
-rw-r--r--lib/gitlab/database/grant.rb2
-rw-r--r--lib/gitlab/gitaly_client.rb3
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb2
-rw-r--r--lib/gitlab/import_export/attribute_cleaner.rb2
-rw-r--r--lib/gitlab/import_export/relation_factory.rb9
-rw-r--r--lib/gitlab/kubernetes/helm/client_command.rb14
-rw-r--r--lib/gitlab/kubernetes/helm/install_command.rb11
-rw-r--r--lib/gitlab/lets_encrypt.rb11
-rw-r--r--lib/gitlab/omniauth_initializer.rb10
-rw-r--r--lib/gitlab/patch/active_record_query_cache.rb39
-rw-r--r--lib/gitlab/regex.rb8
-rw-r--r--lib/gitlab/url_blocker.rb92
-rw-r--r--lib/gitlab/usage_data.rb2
-rw-r--r--lib/gitlab/usage_data_counters/redis_counter.rb19
-rw-r--r--lib/gitlab/usage_data_counters/web_ide_commits_counter.rb13
-rw-r--r--lib/gitlab/web_ide_commits_counter.rb17
-rw-r--r--lib/tasks/gitlab/features.rake14
-rw-r--r--lib/tasks/gitlab/seed.rake7
-rw-r--r--locale/ar_SA/gitlab.po2
-rw-r--r--locale/bg/gitlab.po2
-rw-r--r--locale/bn_BD/gitlab.po2
-rw-r--r--locale/bn_IN/gitlab.po2
-rw-r--r--locale/ca_ES/gitlab.po2
-rw-r--r--locale/cs_CZ/gitlab.po2
-rw-r--r--locale/cy_GB/gitlab.po2
-rw-r--r--locale/da_DK/gitlab.po2
-rw-r--r--locale/de/gitlab.po2
-rw-r--r--locale/el_GR/gitlab.po2
-rw-r--r--locale/eo/gitlab.po2
-rw-r--r--locale/es/gitlab.po2
-rw-r--r--locale/et_EE/gitlab.po2
-rw-r--r--locale/fil_PH/gitlab.po2
-rw-r--r--locale/fr/gitlab.po2
-rw-r--r--locale/gitlab.pot38
-rw-r--r--locale/gl_ES/gitlab.po2
-rw-r--r--locale/he_IL/gitlab.po2
-rw-r--r--locale/hi_IN/gitlab.po2
-rw-r--r--locale/hr_HR/gitlab.po2
-rw-r--r--locale/hu_HU/gitlab.po2
-rw-r--r--locale/id_ID/gitlab.po2
-rw-r--r--locale/it/gitlab.po2
-rw-r--r--locale/ja/gitlab.po2
-rw-r--r--locale/ka_GE/gitlab.po2
-rw-r--r--locale/ko/gitlab.po2
-rw-r--r--locale/mn_MN/gitlab.po2
-rw-r--r--locale/nb_NO/gitlab.po2
-rw-r--r--locale/nl_NL/gitlab.po2
-rw-r--r--locale/pa_IN/gitlab.po2
-rw-r--r--locale/pl_PL/gitlab.po2
-rw-r--r--locale/pt_BR/gitlab.po2
-rw-r--r--locale/pt_PT/gitlab.po2
-rw-r--r--locale/ro_RO/gitlab.po2
-rw-r--r--locale/ru/gitlab.po2
-rw-r--r--locale/sk_SK/gitlab.po2
-rw-r--r--locale/sq_AL/gitlab.po2
-rw-r--r--locale/sr_CS/gitlab.po2
-rw-r--r--locale/sr_SP/gitlab.po2
-rw-r--r--locale/sv_SE/gitlab.po2
-rw-r--r--locale/sw_KE/gitlab.po2
-rw-r--r--locale/tr_TR/gitlab.po2
-rw-r--r--locale/uk/gitlab.po2
-rw-r--r--locale/zh_CN/gitlab.po2
-rw-r--r--locale/zh_HK/gitlab.po2
-rw-r--r--locale/zh_TW/gitlab.po2
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/base.rb2
-rw-r--r--qa/qa/page/element.rb4
-rw-r--r--qa/qa/page/main/menu.rb6
-rw-r--r--qa/qa/page/project/operations/kubernetes/show.rb8
-rw-r--r--qa/qa/resource/kubernetes_cluster.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb3
-rw-r--r--qa/qa/support/retrier.rb6
-rw-r--r--qa/spec/page/element_spec.rb13
-rw-r--r--rubocop/cop/qa/element_with_pattern.rb2
-rwxr-xr-xscripts/gather-test-memory-data21
-rwxr-xr-xscripts/lint-doc.sh4
-rwxr-xr-xscripts/review_apps/review-apps.sh7
-rwxr-xr-xscripts/trigger-build-docs6
-rw-r--r--spec/controllers/admin/application_settings_controller_spec.rb2
-rw-r--r--spec/controllers/admin/runners_controller_spec.rb5
-rw-r--r--spec/controllers/application_controller_spec.rb2
-rw-r--r--spec/controllers/boards/issues_controller_spec.rb24
-rw-r--r--spec/controllers/boards/lists_controller_spec.rb4
-rw-r--r--spec/controllers/groups/boards_controller_spec.rb4
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb2
-rw-r--r--spec/controllers/health_check_controller_spec.rb1
-rw-r--r--spec/controllers/health_controller_spec.rb1
-rw-r--r--spec/controllers/metrics_controller_spec.rb1
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb4
-rw-r--r--spec/controllers/projects/boards_controller_spec.rb4
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb9
-rw-r--r--spec/controllers/projects/commit_controller_spec.rb4
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb9
-rw-r--r--spec/controllers/projects/deploy_keys_controller_spec.rb10
-rw-r--r--spec/controllers/projects/discussions_controller_spec.rb4
-rw-r--r--spec/controllers/projects/environments/prometheus_api_controller_spec.rb2
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb199
-rw-r--r--spec/controllers/projects/find_file_controller_spec.rb5
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb20
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb2
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb4
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb4
-rw-r--r--spec/controllers/projects/templates_controller_spec.rb9
-rw-r--r--spec/controllers/projects/wikis_controller_spec.rb2
-rw-r--r--spec/controllers/projects_controller_spec.rb29
-rw-r--r--spec/controllers/snippets/notes_controller_spec.rb6
-rw-r--r--spec/controllers/snippets_controller_spec.rb2
-rw-r--r--spec/controllers/users_controller_spec.rb2
-rw-r--r--spec/factories/ci/bridge.rb2
-rw-r--r--spec/factories/projects.rb22
-rw-r--r--spec/factories/services.rb6
-rw-r--r--spec/factories/services_data.rb8
-rw-r--r--spec/features/admin/admin_settings_spec.rb35
-rw-r--r--spec/features/markdown/mermaid_spec.rb18
-rw-r--r--spec/features/merge_request/user_creates_merge_request_spec.rb2
-rw-r--r--spec/features/projects/files/user_edits_files_spec.rb1
-rw-r--r--spec/features/projects/fork_spec.rb2
-rw-r--r--spec/features/projects/new_project_spec.rb438
-rw-r--r--spec/features/triggers_spec.rb78
-rw-r--r--spec/fixtures/api/schemas/current-board.json16
-rw-r--r--spec/frontend/boards/services/board_service_spec.js159
-rw-r--r--spec/frontend/create_merge_request_dropdown_spec.js34
-rw-r--r--spec/frontend/repository/components/breadcrumbs_spec.js20
-rw-r--r--spec/helpers/avatars_helper_spec.rb2
-rw-r--r--spec/helpers/blob_helper_spec.rb38
-rw-r--r--spec/helpers/boards_helper_spec.rb16
-rw-r--r--spec/helpers/emails_helper_spec.rb2
-rw-r--r--spec/helpers/icons_helper_spec.rb20
-rw-r--r--spec/helpers/sorting_helper_spec.rb148
-rw-r--r--spec/helpers/visibility_level_helper_spec.rb72
-rw-r--r--spec/javascripts/boards/boards_store_spec.js13
-rw-r--r--spec/javascripts/helpers/vuex_action_helper.js4
-rw-r--r--spec/javascripts/registry/components/app_spec.js2
-rw-r--r--spec/javascripts/test_bundle.js1
-rw-r--r--spec/lib/api/helpers/pagination_spec.rb10
-rw-r--r--spec/lib/banzai/filter/reference_redactor_filter_spec.rb (renamed from spec/lib/banzai/filter/redactor_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/object_renderer_spec.rb8
-rw-r--r--spec/lib/banzai/pipeline/gfm_pipeline_spec.rb6
-rw-r--r--spec/lib/banzai/reference_redactor_spec.rb (renamed from spec/lib/banzai/redactor_spec.rb)2
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb168
-rw-r--r--spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb104
-rw-r--r--spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb98
-rw-r--r--spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb23
-rw-r--r--spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb26
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb44
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb28
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb52
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb4
-rw-r--r--spec/lib/gitlab/email/handler/create_issue_handler_spec.rb1
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb11
-rw-r--r--spec/lib/gitlab/import_export/attribute_cleaner_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/project.json8
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb11
-rw-r--r--spec/lib/gitlab/kubernetes/helm/delete_command_spec.rb16
-rw-r--r--spec/lib/gitlab/kubernetes/helm/install_command_spec.rb12
-rw-r--r--spec/lib/gitlab/lets_encrypt_spec.rb31
-rw-r--r--spec/lib/gitlab/omniauth_initializer_spec.rb28
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb4
-rw-r--r--spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb54
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb2
-rw-r--r--spec/lib/gitlab/web_ide_commits_counter_spec.rb19
-rw-r--r--spec/mailers/emails/pages_domains_spec.rb6
-rw-r--r--spec/migrations/active_record/schema_spec.rb2
-rw-r--r--spec/models/ci/trigger_spec.rb20
-rw-r--r--spec/models/clusters/applications/runner_spec.rb33
-rw-r--r--spec/models/concerns/routable_spec.rb47
-rw-r--r--spec/models/concerns/stepable_spec.rb111
-rw-r--r--spec/models/cycle_analytics/issue_spec.rb2
-rw-r--r--spec/models/cycle_analytics/plan_spec.rb2
-rw-r--r--spec/models/issue/metrics_spec.rb6
-rw-r--r--spec/models/merge_request_spec.rb23
-rw-r--r--spec/models/pages_domain_spec.rb29
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/user_spec.rb32
-rw-r--r--spec/policies/ci/trigger_policy_spec.rb94
-rw-r--r--spec/requests/api/commits_spec.rb2
-rw-r--r--spec/requests/api/group_clusters_spec.rb452
-rw-r--r--spec/requests/api/internal_spec.rb12
-rw-r--r--spec/requests/api/project_clusters_spec.rb16
-rw-r--r--spec/requests/api/search_spec.rb4
-rw-r--r--spec/requests/api/services_spec.rb13
-rw-r--r--spec/requests/api/users_spec.rb8
-rw-r--r--spec/requests/lfs_http_spec.rb4
-rw-r--r--spec/requests/lfs_locks_api_spec.rb4
-rw-r--r--spec/routing/environments_spec.rb9
-rw-r--r--spec/rubocop/cop/qa/element_with_pattern_spec.rb4
-rw-r--r--spec/serializers/environment_status_entity_spec.rb2
-rw-r--r--spec/services/audit_event_service_spec.rb32
-rw-r--r--spec/services/boards/issues/move_service_spec.rb4
-rw-r--r--spec/services/clusters/applications/check_uninstall_progress_service_spec.rb8
-rw-r--r--spec/services/issuable/clone/content_rewriter_spec.rb13
-rw-r--r--spec/services/merge_requests/get_urls_service_spec.rb6
-rw-r--r--spec/services/notification_service_spec.rb2
-rw-r--r--spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb6
-rw-r--r--spec/services/self_monitoring/project/create_service_spec.rb201
-rw-r--r--spec/spec_helper.rb13
-rw-r--r--spec/support/database_cleaner.rb27
-rw-r--r--spec/support/db_cleaner.rb4
-rw-r--r--spec/support/helpers/memory_usage_helper.rb37
-rw-r--r--spec/support/helpers/migrations_helpers.rb13
-rw-r--r--spec/support/helpers/test_env.rb22
-rw-r--r--spec/support/json_response.rb2
-rw-r--r--spec/support/shared_contexts/email_shared_context.rb2
-rw-r--r--spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/policies/clusterable_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/update_invalid_issuable.rb2
-rw-r--r--spec/views/notify/pipeline_failed_email.html.haml_spec.rb4
-rw-r--r--spec/views/notify/pipeline_failed_email.text.erb_spec.rb2
-rw-r--r--spec/views/notify/pipeline_success_email.html.haml_spec.rb4
-rw-r--r--yarn.lock20
680 files changed, 9917 insertions, 6104 deletions
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 2d06a8acc58..c7a51beeee5 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -66,6 +66,8 @@
- scripts/gitaly-test-spawn
- date
- 'export KNAPSACK_TEST_FILE_PATTERN=$(ruby -r./lib/quality/test_level.rb -e "puts Quality::TestLevel.new.pattern(:${TEST_LEVEL})")'
+ - mkdir -p tmp/memory_test
+ - export MEMORY_TEST_PATH="tmp/memory_test/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_memory.csv"
- knapsack rspec "--color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag level:${TEST_LEVEL} --tag ~geo"
- date
artifacts:
@@ -77,6 +79,7 @@
- rspec_flaky/
- rspec_profiling/
- tmp/capybara/
+ - tmp/memory_test/
# reports:
# junit: junit_rspec.xml
@@ -273,6 +276,7 @@ coverage:
stage: post-test
script:
- bundle exec scripts/merge-simplecov
+ - bundle exec scripts/gather-test-memory-data
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
artifacts:
name: coverage
@@ -280,3 +284,4 @@ coverage:
paths:
- coverage/index.html
- coverage/assets/
+ - tmp/memory_test/
diff --git a/.gitlab/issue_templates/Documentation.md b/.gitlab/issue_templates/Documentation.md
index 67602b7b2df..f4070a44755 100644
--- a/.gitlab/issue_templates/Documentation.md
+++ b/.gitlab/issue_templates/Documentation.md
@@ -4,7 +4,7 @@
Note: Doc work as part of feature development is covered in the Feature Request template.
* For issues related to features of the docs.gitlab.com site, see
- https://gitlab.com/gitlab-com/gitlab-docs/issues/
+ https://gitlab.com/gitlab-org/gitlab-docs/issues/
* For information about documentation content and process, see
https://docs.gitlab.com/ee/development/documentation/ -->
diff --git a/.gitlab/merge_request_templates/Change documentation location.md b/.gitlab/merge_request_templates/Change documentation location.md
index c80af95d5e5..7dc80a641c4 100644
--- a/.gitlab/merge_request_templates/Change documentation location.md
+++ b/.gitlab/merge_request_templates/Change documentation location.md
@@ -22,7 +22,7 @@ https://docs.gitlab.com/ce/development/documentation/index.html#changing-documen
- [ ] Make sure internal links pointing to the document in question are not broken.
- [ ] Search and replace any links referring to old docs in GitLab Rails app,
specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories.
-- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/writing_documentation.html#redirections-for-pages-with-disqus-comments)
+- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/documentation/index.html#redirections-for-pages-with-disqus-comments)
to the new document if there are any Disqus comments on the old document thread.
- [ ] Update the link in `features.yml` (if applicable)
- [ ] If working on CE and the `ee-compat-check` jobs fails, submit an MR to EE
diff --git a/.mdlrc b/.mdlrc
index b2127dadc22..151c54f7d44 100644
--- a/.mdlrc
+++ b/.mdlrc
@@ -1,3 +1,6 @@
+# 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
diff --git a/.mdlrc.style b/.mdlrc.style
index 30abf03f462..0ca3611df0b 100644
--- a/.mdlrc.style
+++ b/.mdlrc.style
@@ -1,7 +1,21 @@
+# 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 "MD003", :style => :atx
+rule "MD011"
+rule "MD023"
+rule "MD032"
+rule "MD034"
+rule "MD037"
+
+# Should not be used currently:
-rule 'MD001'
+# rule "MD004", :style => :dash # unordered list style - dash
# False positives, see https://github.com/markdownlint/markdownlint/issues/261
-# rule 'MD004', style: :dash
-rule 'MD032'
-rule 'MD034'
+
+# rule "MD039" # Spaces inside link text
+# Crashes when link text has certain punctuation
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 9c6d6293b1a..bd8bf882d06 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.6.1
+1.7.0
diff --git a/Gemfile b/Gemfile
index 99dce3ba067..7845e9d57fa 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
source 'https://rubygems.org'
-gem 'rails', '5.1.7'
+gem 'rails', '5.2.3'
# Improves copy-on-write performance for MRI
gem 'nakayoshi_fork', '~> 0.0.4'
@@ -431,7 +431,7 @@ group :ed25519 do
end
# Gitaly GRPC client
-gem 'gitaly-proto', '~> 1.36.0', require: 'gitaly'
+gem 'gitaly-proto', '~> 1.37.0', require: 'gitaly'
gem 'grpc', '~> 1.19.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1a3b3b8e125..beded888ffd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -6,44 +6,48 @@ GEM
ace-rails-ap (4.1.2)
acme-client (2.0.2)
faraday (~> 0.9, >= 0.9.1)
- actioncable (5.1.7)
- actionpack (= 5.1.7)
+ actioncable (5.2.3)
+ actionpack (= 5.2.3)
nio4r (~> 2.0)
- websocket-driver (~> 0.6.1)
- actionmailer (5.1.7)
- actionpack (= 5.1.7)
- actionview (= 5.1.7)
- activejob (= 5.1.7)
+ websocket-driver (>= 0.6.1)
+ actionmailer (5.2.3)
+ actionpack (= 5.2.3)
+ actionview (= 5.2.3)
+ activejob (= 5.2.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (5.1.7)
- actionview (= 5.1.7)
- activesupport (= 5.1.7)
+ actionpack (5.2.3)
+ actionview (= 5.2.3)
+ activesupport (= 5.2.3)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (5.1.7)
- activesupport (= 5.1.7)
+ actionview (5.2.3)
+ activesupport (= 5.2.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
- activejob (5.1.7)
- activesupport (= 5.1.7)
+ activejob (5.2.3)
+ activesupport (= 5.2.3)
globalid (>= 0.3.6)
- activemodel (5.1.7)
- activesupport (= 5.1.7)
- activerecord (5.1.7)
- activemodel (= 5.1.7)
- activesupport (= 5.1.7)
- arel (~> 8.0)
+ activemodel (5.2.3)
+ activesupport (= 5.2.3)
+ activerecord (5.2.3)
+ activemodel (= 5.2.3)
+ activesupport (= 5.2.3)
+ arel (>= 9.0)
activerecord-explain-analyze (0.1.0)
activerecord (>= 4)
pg
activerecord_sane_schema_dumper (1.0)
rails (>= 5, < 6)
- activesupport (5.1.7)
+ activestorage (5.2.3)
+ actionpack (= 5.2.3)
+ activerecord (= 5.2.3)
+ marcel (~> 0.3.1)
+ activesupport (5.2.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@@ -60,7 +64,7 @@ GEM
apollo_upload_server (2.0.0.beta.3)
graphql (>= 1.8)
rails (>= 4.2)
- arel (8.0.0)
+ arel (9.0.0)
asana (0.8.1)
faraday (~> 0.9)
faraday_middleware (~> 0.9)
@@ -306,7 +310,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- gitaly-proto (1.36.0)
+ gitaly-proto (1.37.0)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab-labkit (0.3.0)
@@ -504,6 +508,8 @@ GEM
mail (2.7.1)
mini_mime (>= 0.1.1)
mail_room (0.9.1)
+ marcel (0.3.3)
+ mimemagic (~> 0.3.2)
mdl (0.5.0)
kramdown (~> 1.12, >= 1.12.0)
mixlib-cli (~> 1.7, >= 1.7.0)
@@ -706,17 +712,18 @@ GEM
rack-test (1.1.0)
rack (>= 1.0, < 3)
rack-timeout (0.5.1)
- rails (5.1.7)
- actioncable (= 5.1.7)
- actionmailer (= 5.1.7)
- actionpack (= 5.1.7)
- actionview (= 5.1.7)
- activejob (= 5.1.7)
- activemodel (= 5.1.7)
- activerecord (= 5.1.7)
- activesupport (= 5.1.7)
+ rails (5.2.3)
+ actioncable (= 5.2.3)
+ actionmailer (= 5.2.3)
+ actionpack (= 5.2.3)
+ actionview (= 5.2.3)
+ activejob (= 5.2.3)
+ activemodel (= 5.2.3)
+ activerecord (= 5.2.3)
+ activestorage (= 5.2.3)
+ activesupport (= 5.2.3)
bundler (>= 1.3.0)
- railties (= 5.1.7)
+ railties (= 5.2.3)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
@@ -730,12 +737,12 @@ GEM
rails-i18n (5.1.1)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
- railties (5.1.7)
- actionpack (= 5.1.7)
- activesupport (= 5.1.7)
+ railties (5.2.3)
+ actionpack (= 5.2.3)
+ activesupport (= 5.2.3)
method_source
rake (>= 0.8.7)
- thor (>= 0.18.1, < 2.0)
+ thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
raindrops (0.19.0)
rake (12.3.2)
@@ -1019,7 +1026,7 @@ GEM
hashdiff
webpack-rails (0.9.11)
railties (>= 3.2.0)
- websocket-driver (0.6.5)
+ websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
wikicloth (0.8.1)
@@ -1112,7 +1119,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly-proto (~> 1.36.0)
+ gitaly-proto (~> 1.37.0)
github-markup (~> 1.7.0)
gitlab-labkit (~> 0.3.0)
gitlab-markup (~> 1.7.0)
@@ -1206,7 +1213,7 @@ DEPENDENCIES
rack-oauth2 (~> 1.9.3)
rack-proxy (~> 0.6.0)
rack-timeout
- rails (= 5.1.7)
+ rails (= 5.2.3)
rails-controller-testing
rails-i18n (~> 5.1)
rainbow (~> 3.0)
diff --git a/README.md b/README.md
index e64f04cea59..51dc87ac653 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ To see how GitLab looks please see the [features page on our website](https://ab
- Manage Git repositories with fine grained access controls that keep your code secure
- Perform code reviews and enhance collaboration with merge requests
-- Complete continuous integration (CI) and CD pipelines to builds, test, and deploy your applications
+- Complete continuous integration (CI) and continuous deployment/delivery (CD) pipelines to build, test, and deploy your applications
- Each project can also have an issue tracker, issue board, and a wiki
- Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises
- Completely free and open source (MIT Expat license)
diff --git a/app/assets/javascripts/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
index b23de36f860..dbc28beffbe 100644
--- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
@@ -36,7 +36,8 @@ export default function renderMermaid($els) {
});
$els.each((i, el) => {
- const source = el.textContent;
+ // Mermaid doesn't like `<br />` tags, so collapse all like tags into `<br>`, which is parsed correctly.
+ const source = el.textContent.replace(/<br\s*\/>/g, '<br>');
/**
* Restrict the rendering to a certain amount of character to
diff --git a/app/assets/javascripts/boards/components/modal/footer.vue b/app/assets/javascripts/boards/components/modal/footer.vue
index a1d634c8f19..eea0fb71c1a 100644
--- a/app/assets/javascripts/boards/components/modal/footer.vue
+++ b/app/assets/javascripts/boards/components/modal/footer.vue
@@ -41,7 +41,7 @@ export default {
const req = this.buildUpdateRequest(list);
// Post the data to the backend
- gl.boardService.bulkUpdate(issueIds, req).catch(() => {
+ boardsStore.bulkUpdate(issueIds, req).catch(() => {
Flash(__('Failed to update issues, please try again.'));
selectedIssues.forEach(issue => {
diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js
index 580d04a3649..5202620057c 100644
--- a/app/assets/javascripts/boards/services/board_service.js
+++ b/app/assets/javascripts/boards/services/board_service.js
@@ -62,6 +62,22 @@ export default class BoardService {
static toggleIssueSubscription(endpoint) {
return boardsStore.toggleIssueSubscription(endpoint);
}
+
+ allBoards() {
+ return boardsStore.allBoards();
+ }
+
+ recentBoards() {
+ return boardsStore.recentBoards();
+ }
+
+ createBoard(board) {
+ return boardsStore.createBoard(board);
+ }
+
+ deleteBoard({ id }) {
+ return boardsStore.deleteBoard({ id });
+ }
}
window.BoardService = BoardService;
diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js
index b9cd4a143ef..f57c684691c 100644
--- a/app/assets/javascripts/boards/stores/boards_store.js
+++ b/app/assets/javascripts/boards/stores/boards_store.js
@@ -340,6 +340,44 @@ const boardsStore = {
toggleIssueSubscription(endpoint) {
return axios.post(endpoint);
},
+
+ allBoards() {
+ return axios.get(this.generateBoardsPath());
+ },
+
+ recentBoards() {
+ return axios.get(this.state.endpoints.recentBoardsEndpoint);
+ },
+
+ createBoard(board) {
+ const boardPayload = { ...board };
+ boardPayload.label_ids = (board.labels || []).map(b => b.id);
+
+ if (boardPayload.label_ids.length === 0) {
+ boardPayload.label_ids = [''];
+ }
+
+ if (boardPayload.assignee) {
+ boardPayload.assignee_id = boardPayload.assignee.id;
+ }
+
+ if (boardPayload.milestone) {
+ boardPayload.milestone_id = boardPayload.milestone.id;
+ }
+
+ if (boardPayload.id) {
+ return axios.put(this.generateBoardsPath(boardPayload.id), { board: boardPayload });
+ }
+ return axios.post(this.generateBoardsPath(), { board: boardPayload });
+ },
+
+ deleteBoard({ id }) {
+ return axios.delete(this.generateBoardsPath(id));
+ },
+
+ setCurrentBoard(board) {
+ this.state.currentBoard = board;
+ },
};
BoardsStoreEE.initEESpecific(boardsStore);
diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js
index 052168bb21c..dce9c1a5410 100644
--- a/app/assets/javascripts/create_merge_request_dropdown.js
+++ b/app/assets/javascripts/create_merge_request_dropdown.js
@@ -182,7 +182,7 @@ export default class CreateMergeRequestDropdown {
}
enable() {
- if (!canCreateConfidentialMergeRequest()) return;
+ if (isConfidentialIssue() && !canCreateConfidentialMergeRequest()) return;
this.createMergeRequestButton.classList.remove('disabled');
this.createMergeRequestButton.removeAttribute('disabled');
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
index b56e08175cc..d4b994d4922 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
@@ -17,6 +17,7 @@ Vue.use(Translate);
export default () => {
const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
+ const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
// eslint-disable-next-line no-new
new Vue({
@@ -33,7 +34,6 @@ export default () => {
'stage-production-component': stageComponent,
},
data() {
- const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
const cycleAnalyticsService = new CycleAnalyticsService({
requestPath: cycleAnalyticsEl.dataset.requestPath,
});
@@ -56,7 +56,13 @@ export default () => {
},
},
created() {
- this.fetchCycleAnalyticsData();
+ // Conditional check placed here to prevent this method from being called on the
+ // new Cycle Analytics page (i.e. the new page will be initialized blank and only
+ // after a group is selected the cycle analyitcs data will be fetched). Once the
+ // old (current) page has been removed this entire created method as well as the
+ // variable itself can be completely removed.
+ // Follow up issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/64490
+ if (cycleAnalyticsEl.dataset.requestPath) this.fetchCycleAnalyticsData();
},
methods: {
handleError() {
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 63350fafefa..2514274224d 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -67,6 +67,18 @@ export default {
errorMessage() {
return this.file.viewer.error_message;
},
+ forkMessage() {
+ return sprintf(
+ __(
+ "You're not allowed to %{tag_start}edit%{tag_end} files in this project directly. Please fork this project, make your changes there, and submit a merge request.",
+ ),
+ {
+ tag_start: '<span class="js-file-fork-suggestion-section-action">',
+ tag_end: '</span>',
+ },
+ false,
+ );
+ },
},
watch: {
isCollapsed: function fileCollapsedWatch(newVal, oldVal) {
@@ -150,12 +162,7 @@ export default {
/>
<div v-if="forkMessageVisible" class="js-file-fork-suggestion-section file-fork-suggestion">
- <span class="file-fork-suggestion-note">
- {{ sprintf(__("You're not allowed to %{tag_start}edit%{tag_end} files in this project
- directly. Please fork this project, make your changes there, and submit a merge request."),
- { tag_start: '<span class="js-file-fork-suggestion-section-action">', tag_end: '</span>' })
- }}
- </span>
+ <span class="file-fork-suggestion-note" v-html="forkMessage"></span>
<a
:href="file.fork_path"
class="js-fork-suggestion-button btn btn-grouped btn-inverted btn-success"
diff --git a/app/assets/javascripts/issue_show/components/locked_warning.vue b/app/assets/javascripts/issue_show/components/locked_warning.vue
index 2f3e611e089..19c7a11d87b 100644
--- a/app/assets/javascripts/issue_show/components/locked_warning.vue
+++ b/app/assets/javascripts/issue_show/components/locked_warning.vue
@@ -1,18 +1,27 @@
<script>
+import { __, sprintf } from '~/locale';
+
export default {
computed: {
currentPath() {
return window.location.pathname;
},
+ alertMessage() {
+ return sprintf(
+ __(
+ 'Someone edited the issue at the same time you did. Please check out %{linkStart}the issue%{linkEnd} and make sure your changes will not unintentionally remove theirs.',
+ ),
+ {
+ linkStart: `<a href="${this.currentPath}" target="_blank" rel="nofollow">`,
+ linkEnd: `</a>`,
+ },
+ false,
+ );
+ },
},
};
</script>
<template>
- <div class="alert alert-danger">
- {{ sprintf(__("Someone edited the issue at the same time you did. Please check out
- %{linkStart}%the issue%{linkEnd} and make sure your changes will not unintentionally remove
- theirs."), { linkStart: `<a href="${currentPath}" target="_blank" rel="nofollow">` linkEnd: '</a
- >', }) }}
- </div>
+ <div class="alert alert-danger" v-html="alertMessage"></div>
</template>
diff --git a/app/assets/javascripts/notes/components/note_actions/reply_button.vue b/app/assets/javascripts/notes/components/note_actions/reply_button.vue
index be8e42af9ea..1aeb07d6608 100644
--- a/app/assets/javascripts/notes/components/note_actions/reply_button.vue
+++ b/app/assets/javascripts/notes/components/note_actions/reply_button.vue
@@ -19,7 +19,7 @@ export default {
<gl-button
ref="button"
v-gl-tooltip
- class="note-action-button"
+ class="note-action-button js-note-action-reply"
variant="transparent"
:title="__('Reply to comment')"
@click="$emit('startReplying')"
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 30eab272aa9..762a87ce0ff 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -357,11 +357,11 @@ export const poll = ({ commit, state, getters, dispatch }) => {
};
export const stopPolling = () => {
- eTagPoll.stop();
+ if (eTagPoll) eTagPoll.stop();
};
export const restartPolling = () => {
- eTagPoll.restart();
+ if (eTagPoll) eTagPoll.restart();
};
export const fetchData = ({ commit, state, getters }) => {
diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue
index 7752723baac..38519c220c5 100644
--- a/app/assets/javascripts/registry/components/app.vue
+++ b/app/assets/javascripts/registry/components/app.vue
@@ -2,6 +2,7 @@
import { mapGetters, mapActions } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import store from '../stores';
+import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
import CollapsibleContainer from './collapsible_container.vue';
import SvgMessage from './svg_message.vue';
import { s__, sprintf } from '../../locale';
@@ -9,6 +10,7 @@ import { s__, sprintf } from '../../locale';
export default {
name: 'RegistryListApp',
components: {
+ clipboardButton,
CollapsibleContainer,
GlLoadingIcon,
SvgMessage,
@@ -46,10 +48,10 @@ export default {
dockerConnectionErrorText() {
return sprintf(
s__(`ContainerRegistry|We are having trouble connecting to Docker, which could be due to an
- issue with your project name or path. For more information, please review the
- %{docLinkStart}Container Registry documentation%{docLinkEnd}.`),
+ issue with your project name or path.
+ %{docLinkStart}More Information%{docLinkEnd}`),
{
- docLinkStart: `<a href="${this.helpPagePath}#docker-connection-error">`,
+ docLinkStart: `<a href="${this.helpPagePath}#docker-connection-error" target="_blank">`,
docLinkEnd: '</a>',
},
false,
@@ -58,10 +60,10 @@ export default {
introText() {
return sprintf(
s__(`ContainerRegistry|With the Docker Container Registry integrated into GitLab, every
- project can have its own space to store its Docker images. Learn more about the
- %{docLinkStart}Container Registry%{docLinkEnd}.`),
+ project can have its own space to store its Docker images.
+ %{docLinkStart}More Information%{docLinkEnd}`),
{
- docLinkStart: `<a href="${this.helpPagePath}">`,
+ docLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
docLinkEnd: '</a>',
},
false,
@@ -70,14 +72,20 @@ export default {
noContainerImagesText() {
return sprintf(
s__(`ContainerRegistry|With the Container Registry, every project can have its own space to
- store its Docker images. Learn more about the %{docLinkStart}Container Registry%{docLinkEnd}.`),
+ store its Docker images. %{docLinkStart}More Information%{docLinkEnd}`),
{
- docLinkStart: `<a href="${this.helpPagePath}">`,
+ docLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
docLinkEnd: '</a>',
},
false,
);
},
+ dockerBuildCommand() {
+ return `docker build -t ${this.repositoryUrl} .`;
+ },
+ dockerPushCommand() {
+ return `docker push ${this.repositoryUrl}`;
+ },
},
created() {
this.setMainEndpoint(this.endpoint);
@@ -99,7 +107,7 @@ export default {
<p v-html="dockerConnectionErrorText"></p>
</svg-message>
- <gl-loading-icon v-else-if="isLoading" size="md" class="prepend-top-16" />
+ <gl-loading-icon v-else-if="isLoading && !characterError" size="md" class="prepend-top-16" />
<div v-else-if="!isLoading && !characterError && repos.length">
<h4>{{ s__('ContainerRegistry|Container Registry') }}</h4>
@@ -126,10 +134,27 @@ export default {
}}
</p>
- <pre>
- docker build -t {{ repositoryUrl }} .
- docker push {{ repositoryUrl }}
- </pre>
+ <div class="input-group append-bottom-10">
+ <input :value="dockerBuildCommand" type="text" class="form-control monospace" readonly />
+ <span class="input-group-append">
+ <clipboard-button
+ :text="dockerBuildCommand"
+ :title="s__('ContainerRegistry|Copy build command to clipboard')"
+ class="input-group-text"
+ />
+ </span>
+ </div>
+
+ <div class="input-group">
+ <input :value="dockerPushCommand" type="text" class="form-control monospace" readonly />
+ <span class="input-group-append">
+ <clipboard-button
+ :text="dockerPushCommand"
+ :title="s__('ContainerRegistry|Copy push command to clipboard')"
+ class="input-group-text"
+ />
+ </span>
+ </div>
</svg-message>
</div>
</template>
diff --git a/app/assets/javascripts/registry/components/svg_message.vue b/app/assets/javascripts/registry/components/svg_message.vue
index d0d44bf2d14..617093e054e 100644
--- a/app/assets/javascripts/registry/components/svg_message.vue
+++ b/app/assets/javascripts/registry/components/svg_message.vue
@@ -15,10 +15,12 @@ export default {
</script>
<template>
- <div :id="id" class="empty-state container-message mw-70p">
+ <div :id="id" class="empty-state container-message">
<div class="svg-content">
<img :src="svgPath" class="flex-align-self-center" />
</div>
- <slot></slot>
+ <div class="text-content">
+ <slot></slot>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/related_merge_requests/components/related_merge_requests.vue b/app/assets/javascripts/related_merge_requests/components/related_merge_requests.vue
index 6d908524da9..f0112a5a623 100644
--- a/app/assets/javascripts/related_merge_requests/components/related_merge_requests.vue
+++ b/app/assets/javascripts/related_merge_requests/components/related_merge_requests.vue
@@ -65,7 +65,7 @@ export default {
<template>
<div v-if="isFetchingMergeRequests || (!isFetchingMergeRequests && totalCount)">
- <div id="merge-requests" class="card-slim mt-3">
+ <div id="merge-requests" class="card card-slim mt-3">
<div class="card-header">
<div class="card-title mt-0 mb-0 h5 merge-requests-title">
<span class="mr-1">
diff --git a/app/assets/javascripts/reports/components/issue_status_icon.vue b/app/assets/javascripts/reports/components/issue_status_icon.vue
index 04fba43b2f3..386653b9444 100644
--- a/app/assets/javascripts/reports/components/issue_status_icon.vue
+++ b/app/assets/javascripts/reports/components/issue_status_icon.vue
@@ -16,7 +16,7 @@ export default {
statusIconSize: {
type: Number,
required: false,
- default: 32,
+ default: 24,
},
},
computed: {
diff --git a/app/assets/javascripts/reports/components/report_item.vue b/app/assets/javascripts/reports/components/report_item.vue
index 2be9c37b00a..d477fafd3f5 100644
--- a/app/assets/javascripts/reports/components/report_item.vue
+++ b/app/assets/javascripts/reports/components/report_item.vue
@@ -27,7 +27,7 @@ export default {
statusIconSize: {
type: Number,
required: false,
- default: 32,
+ default: 24,
},
isNew: {
type: Boolean,
@@ -43,12 +43,15 @@ export default {
};
</script>
<template>
- <li :class="{ 'is-dismissed': issue.isDismissed }" class="report-block-list-issue">
+ <li
+ :class="{ 'is-dismissed': issue.isDismissed }"
+ class="report-block-list-issue justify-content-center align-items-center"
+ >
<issue-status-icon
v-if="showReportSectionStatusIcon"
:status="status"
:status-icon-size="statusIconSize"
- class="append-right-5"
+ class="append-right-default"
/>
<component :is="component" v-if="component" :issue="issue" :status="status" :is-new="isNew" />
diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue
index 3d576caaf8f..9bc3e6388e3 100644
--- a/app/assets/javascripts/reports/components/report_section.vue
+++ b/app/assets/javascripts/reports/components/report_section.vue
@@ -165,8 +165,8 @@ export default {
<template>
<section class="media-section">
<div class="media">
- <status-icon :status="statusIconName" />
- <div class="media-body d-flex flex-align-self-center">
+ <status-icon :status="statusIconName" :size="24" />
+ <div class="media-body d-flex flex-align-self-center prepend-left-default">
<span class="js-code-text code-text">
{{ headerText }}
<slot :name="slotName"></slot>
diff --git a/app/assets/javascripts/reports/components/summary_row.vue b/app/assets/javascripts/reports/components/summary_row.vue
index 97a68531d29..1caf52431e2 100644
--- a/app/assets/javascripts/reports/components/summary_row.vue
+++ b/app/assets/javascripts/reports/components/summary_row.vue
@@ -44,10 +44,16 @@ export default {
};
</script>
<template>
- <div class="report-block-list-issue report-block-list-issue-parent">
- <div class="report-block-list-icon append-right-10 prepend-left-5">
- <gl-loading-icon v-if="statusIcon === 'loading'" css-class="report-block-list-loading-icon" />
- <ci-icon v-else :status="iconStatus" />
+ <div
+ class="report-block-list-issue report-block-list-issue-parent justify-content-center align-items-center"
+ >
+ <div class="report-block-list-icon append-right-default">
+ <gl-loading-icon
+ v-if="statusIcon === 'loading'"
+ css-class="report-block-list-loading-icon"
+ size="md"
+ />
+ <ci-icon v-else :status="iconStatus" :size="24" />
</div>
<div class="report-block-list-issue-description">
diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue
index 67963dc1923..afb58a60155 100644
--- a/app/assets/javascripts/repository/components/breadcrumbs.vue
+++ b/app/assets/javascripts/repository/components/breadcrumbs.vue
@@ -1,12 +1,41 @@
<script>
+import { GlDropdown, GlDropdownDivider, GlDropdownHeader, GlDropdownItem } from '@gitlab/ui';
+import { __ } from '../../locale';
+import Icon from '../../vue_shared/components/icon.vue';
import getRefMixin from '../mixins/get_ref';
import getProjectShortPath from '../queries/getProjectShortPath.query.graphql';
+import getProjectPath from '../queries/getProjectPath.query.graphql';
+import getPermissions from '../queries/getPermissions.query.graphql';
+
+const ROW_TYPES = {
+ header: 'header',
+ divider: 'divider',
+};
export default {
+ components: {
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownHeader,
+ GlDropdownItem,
+ Icon,
+ },
apollo: {
projectShortPath: {
query: getProjectShortPath,
},
+ projectPath: {
+ query: getProjectPath,
+ },
+ userPermissions: {
+ query: getPermissions,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ };
+ },
+ update: data => data.project.userPermissions,
+ },
},
mixins: [getRefMixin],
props: {
@@ -15,10 +44,52 @@ export default {
required: false,
default: '/',
},
+ canCollaborate: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ canEditTree: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ newBranchPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ newTagPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ newBlobPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ forkNewBlobPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ forkNewDirectoryPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ forkUploadBlobPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
data() {
return {
projectShortPath: '',
+ projectPath: '',
+ userPermissions: {},
};
},
computed: {
@@ -39,11 +110,112 @@ export default {
[{ name: this.projectShortPath, path: '/', to: `/tree/${this.ref}/` }],
);
},
+ canCreateMrFromFork() {
+ return this.userPermissions.forkProject && this.userPermissions.createMergeRequestIn;
+ },
+ dropdownItems() {
+ const items = [];
+
+ if (this.canEditTree) {
+ items.push(
+ {
+ type: ROW_TYPES.header,
+ text: __('This directory'),
+ },
+ {
+ attrs: {
+ href: this.newBlobPath,
+ class: 'qa-new-file-option',
+ },
+ text: __('New file'),
+ },
+ {
+ attrs: {
+ href: '#modal-upload-blob',
+ 'data-target': '#modal-upload-blob',
+ 'data-toggle': 'modal',
+ },
+ text: __('Upload file'),
+ },
+ {
+ attrs: {
+ href: '#modal-create-new-dir',
+ 'data-target': '#modal-create-new-dir',
+ 'data-toggle': 'modal',
+ },
+ text: __('New directory'),
+ },
+ );
+ } else if (this.canCreateMrFromFork) {
+ items.push(
+ {
+ attrs: {
+ href: this.forkNewBlobPath,
+ 'data-method': 'post',
+ },
+ text: __('New file'),
+ },
+ {
+ attrs: {
+ href: this.forkUploadBlobPath,
+ 'data-method': 'post',
+ },
+ text: __('Upload file'),
+ },
+ {
+ attrs: {
+ href: this.forkNewDirectoryPath,
+ 'data-method': 'post',
+ },
+ text: __('New directory'),
+ },
+ );
+ }
+
+ if (this.userPermissions.pushCode) {
+ items.push(
+ {
+ type: ROW_TYPES.divider,
+ },
+ {
+ type: ROW_TYPES.header,
+ text: __('This repository'),
+ },
+ {
+ attrs: {
+ href: this.newBranchPath,
+ },
+ text: __('New branch'),
+ },
+ {
+ attrs: {
+ href: this.newTagPath,
+ },
+ text: __('New tag'),
+ },
+ );
+ }
+
+ return items;
+ },
+ renderAddToTreeDropdown() {
+ return this.canCollaborate || this.canCreateMrFromFork;
+ },
},
methods: {
isLast(i) {
return i === this.pathLinks.length - 1;
},
+ getComponent(type) {
+ switch (type) {
+ case ROW_TYPES.divider:
+ return 'gl-dropdown-divider';
+ case ROW_TYPES.header:
+ return 'gl-dropdown-header';
+ default:
+ return 'gl-dropdown-item';
+ }
+ },
},
};
</script>
@@ -56,6 +228,20 @@ export default {
{{ link.name }}
</router-link>
</li>
+ <li v-if="renderAddToTreeDropdown" class="breadcrumb-item">
+ <gl-dropdown toggle-class="add-to-tree qa-add-to-tree ml-1">
+ <template slot="button-content">
+ <span class="sr-only">{{ __('Add to tree') }}</span>
+ <icon name="plus" :size="16" class="float-left" />
+ <icon name="arrow-down" :size="16" class="float-left" />
+ </template>
+ <template v-for="(item, i) in dropdownItems">
+ <component :is="getComponent(item.type)" :key="i" v-bind="item.attrs">
+ {{ item.text }}
+ </component>
+ </template>
+ </gl-dropdown>
+ </li>
</ol>
</nav>
</template>
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index ea051eaa414..f9727960040 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -5,6 +5,7 @@ import Breadcrumbs from './components/breadcrumbs.vue';
import LastCommit from './components/last_commit.vue';
import apolloProvider from './graphql';
import { setTitle } from './utils/title';
+import { parseBoolean } from '../lib/utils/common_utils';
export default function setupVueRepositoryList() {
const el = document.getElementById('js-tree-list');
@@ -36,19 +37,42 @@ export default function setupVueRepositoryList() {
.forEach(elem => elem.classList.toggle('hidden', !isRoot));
});
- // eslint-disable-next-line no-new
- new Vue({
- el: document.getElementById('js-repo-breadcrumb'),
- router,
- apolloProvider,
- render(h) {
- return h(Breadcrumbs, {
- props: {
- currentPath: this.$route.params.pathMatch,
- },
- });
- },
- });
+ const breadcrumbEl = document.getElementById('js-repo-breadcrumb');
+
+ if (breadcrumbEl) {
+ const {
+ canCollaborate,
+ canEditTree,
+ newBranchPath,
+ newTagPath,
+ newBlobPath,
+ forkNewBlobPath,
+ forkNewDirectoryPath,
+ forkUploadBlobPath,
+ } = breadcrumbEl.dataset;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: breadcrumbEl,
+ router,
+ apolloProvider,
+ render(h) {
+ return h(Breadcrumbs, {
+ props: {
+ currentPath: this.$route.params.pathMatch,
+ canCollaborate: parseBoolean(canCollaborate),
+ canEditTree: parseBoolean(canEditTree),
+ newBranchPath,
+ newTagPath,
+ newBlobPath,
+ forkNewBlobPath,
+ forkNewDirectoryPath,
+ forkUploadBlobPath,
+ },
+ });
+ },
+ });
+ }
// eslint-disable-next-line no-new
new Vue({
diff --git a/app/assets/javascripts/repository/queries/getPermissions.query.graphql b/app/assets/javascripts/repository/queries/getPermissions.query.graphql
new file mode 100644
index 00000000000..092fa44e2d0
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/getPermissions.query.graphql
@@ -0,0 +1,9 @@
+query getPermissions($projectPath: ID!) {
+ project(fullPath: $projectPath) {
+ userPermissions {
+ pushCode
+ forkProject
+ createMergeRequestIn
+ }
+ }
+}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue
index 4b57693e8f1..57d4d8b7ae6 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue
@@ -14,6 +14,6 @@ export default {
<template>
<div class="circle-icon-container append-right-default align-self-start align-self-lg-center">
- <icon :name="name" />
+ <icon :name="name" :size="24" />
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
index f5fa68308bc..40c095aa954 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -96,16 +96,14 @@ export default {
<template>
<div class="ci-widget media js-ci-widget">
<template v-if="!hasPipeline || hasCIError">
- <div
- class="add-border ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-default"
- >
- <icon :size="32" name="status_failed_borderless" />
+ <div class="add-border ci-status-icon ci-status-icon-failed ci-error js-ci-error">
+ <icon :size="24" name="status_failed_borderless" />
</div>
- <div class="media-body" v-html="errorText"></div>
+ <div class="media-body prepend-left-default" v-html="errorText"></div>
</template>
<template v-else-if="hasPipeline">
<a :href="status.details_path" class="align-self-start append-right-default">
- <ci-icon :status="status" :size="32" :borderless="true" class="add-border" />
+ <ci-icon :status="status" :size="24" :borderless="true" class="add-border" />
</a>
<div class="ci-widget-container d-flex">
<div class="ci-widget-content">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
index 392eb6fb425..8dbd9e52cfe 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
@@ -32,8 +32,8 @@ export default {
};
</script>
<template>
- <div class="space-children d-flex append-right-10 widget-status-icon">
- <div v-if="isLoading" class="mr-widget-icon"><gl-loading-icon size="md" /></div>
+ <div class="d-flex widget-status-icon">
+ <div v-if="isLoading" class="mr-widget-icon"><gl-loading-icon size="sm" /></div>
<ci-icon v-else :status="statusObj" :size="24" />
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
index 0312b147b62..01524f4b650 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
@@ -83,7 +83,7 @@ export default {
<gl-button
:aria-label="ariaLabel"
variant="blank"
- class="commit-edit-toggle square s24 mr-2"
+ class="commit-edit-toggle square s24 append-right-default"
@click.stop="toggle()"
>
<icon :name="collapseIcon" :size="16" />
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
index 7312b31c01c..4d7d49398eb 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
@@ -18,7 +18,9 @@ export default {
<template>
<div class="mr-widget-body mr-widget-empty-state">
<div class="row">
- <div class="artwork col-md-5 order-md-last col-12 text-center">
+ <div
+ class="artwork col-md-5 order-md-last col-12 text-center d-flex justify-content-center align-items-center"
+ >
<span v-html="emptyStateSVG"></span>
</div>
<div class="text col-md-7 order-md-first col-12">
diff --git a/app/assets/stylesheets/components/avatar.scss b/app/assets/stylesheets/components/avatar.scss
index 8e9650cdf34..312123aeef9 100644
--- a/app/assets/stylesheets/components/avatar.scss
+++ b/app/assets/stylesheets/components/avatar.scss
@@ -50,6 +50,11 @@ $avatar-sizes: (
line-height: 88px,
border-radius: $border-radius-large
),
+ 96: (
+ font-size: 36px,
+ line-height: 94px,
+ border-radius: $border-radius-large
+ ),
100: (
font-size: 36px,
line-height: 98px,
diff --git a/app/assets/stylesheets/components/popover.scss b/app/assets/stylesheets/components/popover.scss
index 8c40c4adb5c..6654553aaa2 100644
--- a/app/assets/stylesheets/components/popover.scss
+++ b/app/assets/stylesheets/components/popover.scss
@@ -102,6 +102,7 @@
.onboarding-popover {
box-shadow: 0 2px 4px $dropdown-shadow-color;
+ max-width: 280px;
.popover-body {
font-size: $gl-font-size;
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 9b1d9d51f9c..82b4ec750ff 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -9,7 +9,6 @@
@import 'framework/animations';
@import 'framework/vue_transitions';
-@import 'framework/asciidoctor';
@import 'framework/banner';
@import 'framework/blocks';
@import 'framework/buttons';
diff --git a/app/assets/stylesheets/framework/asciidoctor.scss b/app/assets/stylesheets/framework/asciidoctor.scss
deleted file mode 100644
index 1586265d40e..00000000000
--- a/app/assets/stylesheets/framework/asciidoctor.scss
+++ /dev/null
@@ -1,27 +0,0 @@
-.admonitionblock td.icon {
- width: 1%;
-
- [class^='fa icon-'] {
- @extend .fa-2x;
- }
-
- .icon-note {
- @extend .fa-thumb-tack;
- }
-
- .icon-tip {
- @extend .fa-lightbulb-o;
- }
-
- .icon-warning {
- @extend .fa-exclamation-triangle;
- }
-
- .icon-caution {
- @extend .fa-fire;
- }
-
- .icon-important {
- @extend .fa-exclamation-circle;
- }
-}
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 26cbb7f5c13..5984efd1cf8 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -9,14 +9,14 @@
float: right;
margin-right: 0;
- @include media-breakpoint-down(xs) {
+ @include media-breakpoint-down(sm) {
float: none;
}
}
}
.filters-section {
- @include media-breakpoint-down(xs) {
+ @include media-breakpoint-down(sm) {
display: inline-block;
}
}
@@ -37,7 +37,7 @@
}
}
-@include media-breakpoint-down(xs) {
+@include media-breakpoint-down(sm) {
.filter-item {
display: block;
margin: 0 0 10px;
@@ -50,12 +50,6 @@
}
.filtered-search-wrapper {
- display: flex;
-
- @include media-breakpoint-down(xs) {
- flex-direction: column;
- }
-
.tokens-container {
display: flex;
flex: 1;
@@ -186,7 +180,7 @@
border: 1px solid $border-color;
background-color: $white-light;
- @include media-breakpoint-down(xs) {
+ @include media-breakpoint-down(sm) {
flex: 1 1 auto;
margin-bottom: 10px;
}
@@ -259,7 +253,7 @@
max-width: 280px;
overflow: auto;
- @include media-breakpoint-down(xs) {
+ @include media-breakpoint-down(sm) {
width: auto;
left: 0;
right: 0;
@@ -311,7 +305,7 @@
.filtered-search-history-dropdown {
width: 40%;
- @include media-breakpoint-down(xs) {
+ @include media-breakpoint-down(sm) {
left: 0;
right: 0;
max-width: none;
@@ -341,35 +335,46 @@
}
.filter-dropdown-container {
- display: flex;
-
.dropdown-toggle {
line-height: 22px;
}
}
-@include media-breakpoint-down(xs) {
+@include media-breakpoint-down(sm) {
.issues-details-filters {
- padding: 0 0 10px;
+ padding-top: 0;
+ padding-bottom: 0;
background-color: $white-light;
border-top: 0;
}
- .filter-dropdown-container {
+ .boards-switcher {
+ margin: 0 0 10px;
+
+ .boards-selector-wrapper,
.dropdown {
- margin-left: 0;
+ display: block;
}
}
-}
-@include media-breakpoint-down(sm) {
- .filter-dropdown-container {
- .dropdown-toggle,
- .dropdown,
- .dropdown-menu {
+ .filter-dropdown-container > div {
+ margin: 0;
+
+ > .btn {
+ margin: 0 0 10px;
width: 100%;
}
}
+
+ .boards-add-list > .btn {
+ text-align: left;
+
+ > svg {
+ position: absolute;
+ top: 11px;
+ right: 6px;
+ }
+ }
}
.droplab-dropdown .dropdown-menu .filter-dropdown-item {
diff --git a/app/assets/stylesheets/framework/icons.scss b/app/assets/stylesheets/framework/icons.scss
index 1be5ef276fd..7332c4981d2 100644
--- a/app/assets/stylesheets/framework/icons.scss
+++ b/app/assets/stylesheets/framework/icons.scss
@@ -88,8 +88,5 @@
display: flex;
align-items: center;
justify-content: center;
- border: $border-size solid $gray-400;
- border-radius: 50%;
- padding: $gl-padding-8 - $border-size;
color: $gray-700;
}
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index b721b90fbb3..fd9a75bc5b6 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -19,16 +19,23 @@
}
}
- // leave enough space for the close icon
.modal-title {
+ line-height: $gl-line-height-24;
+
+ // leave enough space for the close icon
&.mw-100,
&.w-100 {
- // after upgrading to Bootstrap 4.2 we can use $modal-header-padding-x here
- // https://github.com/twbs/bootstrap/pull/26976
- margin-right: -28px;
- padding-right: 28px;
+ margin-right: -$modal-header-padding-x;
+ padding-right: $modal-header-padding-x;
}
}
+
+ .close {
+ font-weight: $gl-font-weight-normal;
+ line-height: $gl-line-height;
+ color: $gray-900;
+ opacity: 1;
+ }
}
.modal-body {
@@ -63,6 +70,10 @@
margin-left: $grid-size;
}
+ .btn-group .btn + .btn {
+ margin-left: -1px;
+ }
+
@include media-breakpoint-down(xs) {
flex-direction: column;
@@ -72,6 +83,11 @@
margin-left: 0;
margin-top: $grid-size;
}
+
+ .btn-group .btn + .btn {
+ margin-left: -1px;
+ margin-top: 0;
+ }
}
}
@@ -93,12 +109,12 @@ body.modal-open {
.modal-content {
border-radius: $modal-border-radius;
- *:first-child {
+ > :first-child {
border-top-left-radius: $modal-border-radius;
border-top-right-radius: $modal-border-radius;
}
- *:last-child {
+ > :last-child {
border-bottom-left-radius: $modal-border-radius;
border-bottom-right-radius: $modal-border-radius;
}
diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss
index cd3d6f8297e..d9c93fed1c4 100644
--- a/app/assets/stylesheets/framework/panels.scss
+++ b/app/assets/stylesheets/framework/panels.scss
@@ -3,7 +3,6 @@
}
.card-slim {
- @extend .card;
margin-bottom: $gl-vert-padding;
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 7baab478034..c201605e83d 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -1,5 +1,5 @@
/**
- * Apply Markdown typography
+ * Apply Markup (Markdown/AsciiDoc) typography
*
*/
.md:not(.use-csslab) {
@@ -245,6 +245,21 @@
}
}
+ ul.checklist,
+ ul.none,
+ ol.none,
+ ul.no-bullet,
+ ol.no-bullet,
+ ol.unnumbered,
+ ul.unstyled,
+ ol.unstyled {
+ list-style-type: none;
+
+ li {
+ margin-left: 0;
+ }
+ }
+
li {
line-height: 1.6em;
margin-left: 25px;
@@ -321,6 +336,54 @@
visibility: visible;
}
}
+
+ .big {
+ font-size: larger;
+ }
+
+ .small {
+ font-size: smaller;
+ }
+
+ .underline {
+ text-decoration: underline;
+ }
+
+ .overline {
+ text-decoration: overline;
+ }
+
+ .line-through {
+ text-decoration: line-through;
+ }
+
+ .admonitionblock td.icon {
+ width: 1%;
+
+ [class^='fa icon-'] {
+ @extend .fa-2x;
+ }
+
+ .icon-note {
+ @extend .fa-thumb-tack;
+ }
+
+ .icon-tip {
+ @extend .fa-lightbulb-o;
+ }
+
+ .icon-warning {
+ @extend .fa-exclamation-triangle;
+ }
+
+ .icon-caution {
+ @extend .fa-fire;
+ }
+
+ .icon-important {
+ @extend .fa-exclamation-circle;
+ }
+ }
}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index ffc6e433988..3d11aa58871 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -167,7 +167,7 @@
min-width: 0;
.project-namespace {
- color: $gl-text-color-secondary;
+ color: $gl-text-color-tertiary;
}
}
diff --git a/app/assets/stylesheets/pages/container_registry.scss b/app/assets/stylesheets/pages/container_registry.scss
index cca5214a508..a21fa29f34a 100644
--- a/app/assets/stylesheets/pages/container_registry.scss
+++ b/app/assets/stylesheets/pages/container_registry.scss
@@ -6,6 +6,10 @@
pre {
white-space: pre-line;
}
+
+ span .btn {
+ margin: 0;
+ }
}
.container-image {
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 3ffe8ae304d..95ea49ad465 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -14,7 +14,7 @@
position: -webkit-sticky;
position: sticky;
top: $mr-file-header-top;
- z-index: 220;
+ z-index: 120;
&::before {
content: '';
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index 7610c5cf6f3..ef872e693e0 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -38,3 +38,9 @@
.documentation {
padding: 7px;
}
+
+.card.links-card {
+ a {
+ color: $blue-600;
+ }
+}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 3917937f4af..2780afa11fa 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -10,8 +10,8 @@
float: left;
}
- > *:not(:last-child) {
- margin-right: 10px;
+ > *:not(:first-child) {
+ margin-left: 10px;
}
}
@@ -69,7 +69,7 @@
content: '';
border-left: 1px solid $gray-200;
position: absolute;
- left: 32px;
+ left: 28px;
top: -17px;
height: 16px;
}
@@ -114,7 +114,7 @@
padding: $gl-padding;
@include media-breakpoint-up(md) {
- padding-left: $gl-padding-50;
+ padding-left: $gl-padding-8 * 7;
}
}
}
@@ -264,6 +264,10 @@
.widget-status-icon {
align-self: flex-start;
+
+ button {
+ margin-left: $gl-padding;
+ }
}
.mr-widget-body {
@@ -271,8 +275,8 @@
@include clearfix;
- &.media > *:first-child {
- margin-right: 10px;
+ button {
+ margin-left: $gl-padding;
}
.approve-btn {
@@ -312,6 +316,7 @@
.bold {
font-weight: $gl-font-weight-bold;
color: $gl-gray-light;
+ margin-left: 10px;
}
.state-label {
@@ -377,9 +382,13 @@
&.mr-widget-empty-state {
line-height: 20px;
+ padding: $gl-padding;
.artwork {
- margin-bottom: $gl-padding;
+
+ @include media-breakpoint-down(md) {
+ margin-bottom: $gl-padding;
+ }
}
.text {
@@ -395,7 +404,7 @@
}
.mr-widget-help {
- padding: 10px 16px 10px $gl-padding-50;
+ padding: 10px 16px 10px ($gl-padding-8 * 7);
font-style: italic;
}
@@ -913,7 +922,7 @@
.media-body {
min-width: 0;
font-size: 12px;
- margin-left: 48px;
+ margin-left: 40px;
}
&:not(:last-child) {
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index aa6bbc8e473..ff4fa8aacdc 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -588,8 +588,8 @@
}
.ci-status-icon svg {
- height: 20px;
- width: 20px;
+ height: 24px;
+ width: 24px;
}
.dropdown-menu-toggle {
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 73ba09dbba5..09a576c11cb 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -303,7 +303,7 @@
.count-badge-count,
.count-badge-button {
- border: 1px solid $border-color;
+ border: 1px solid $gray-400;
line-height: 1;
}
diff --git a/app/assets/stylesheets/pages/reports.scss b/app/assets/stylesheets/pages/reports.scss
index 94da72622af..85e9f303dde 100644
--- a/app/assets/stylesheets/pages/reports.scss
+++ b/app/assets/stylesheets/pages/reports.scss
@@ -57,7 +57,7 @@
.report-block-container {
border-top: 1px solid $border-color;
- padding: $gl-padding-top;
+ padding: $gl-padding - 2;
background-color: $gray-light;
// Clean MR widget CSS
@@ -96,17 +96,14 @@
.ci-status-icon {
svg {
- width: 16px;
- height: 16px;
- left: -2px;
+ width: 24px;
+ height: 24px;
}
}
}
.report-block-list-issue {
display: flex;
- align-items: flex-start;
- align-content: flex-start;
}
.is-dismissed .report-block-list-issue-description,
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index a570da61d54..e9ec8876688 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -103,7 +103,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
[
*::ApplicationSettingsHelper.visible_attributes,
*::ApplicationSettingsHelper.external_authorization_service_attributes,
- *lets_encrypt_visible_attributes,
+ :lets_encrypt_notification_email,
+ :lets_encrypt_terms_of_service_accepted,
:domain_blacklist_file,
disabled_oauth_sign_in_sources: [],
import_sources: [],
@@ -143,13 +144,4 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
render action
end
-
- def lets_encrypt_visible_attributes
- return [] unless Feature.enabled?(:pages_auto_ssl)
-
- [
- :lets_encrypt_notification_email,
- :lets_encrypt_terms_of_service_accepted
- ]
- end
end
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index 353a9806fd1..90528f75ffd 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -58,11 +58,8 @@ module Boards
service = Boards::Issues::MoveService.new(board_parent, current_user, move_params(true))
issues = Issue.find(params[:ids])
- if service.execute_multiple(issues)
- head :ok
- else
- head :unprocessable_entity
- end
+
+ render json: service.execute_multiple(issues)
end
def update
diff --git a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
index f47ead2f0da..2e9905997db 100644
--- a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
+++ b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
@@ -28,7 +28,7 @@ module RequiresWhitelistedMonitoringClient
def valid_token?
token = params[:token].presence || request.headers['TOKEN']
token.present? &&
- ActiveSupport::SecurityUtils.variable_size_secure_compare(
+ ActiveSupport::SecurityUtils.secure_compare(
token,
Gitlab::CurrentSettings.health_check_access_token
)
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 797833e3f91..dbddee47997 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -107,7 +107,7 @@ class GroupsController < Groups::ApplicationController
if Groups::UpdateService.new(@group, current_user, group_params).execute
redirect_to edit_group_path(@group, anchor: params[:update_section]), notice: "Group '#{@group.name}' was successfully updated."
else
- @group.restore_path!
+ @group.path = @group.path_before_last_save || @group.path_was
render action: "edit"
end
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 1bca52106fa..ccd54b369fa 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -160,20 +160,22 @@ class Projects::EnvironmentsController < Projects::ApplicationController
end
def metrics_dashboard
- return render_403 unless Feature.enabled?(:environment_metrics_use_prometheus_endpoint, project)
-
- if Feature.enabled?(:environment_metrics_show_multiple_dashboards, project)
+ if Feature.enabled?(:gfm_embedded_metrics, project) && params[:embedded]
result = dashboard_finder.find(
project,
current_user,
environment,
- dashboard_path: params[:dashboard],
embedded: params[:embedded]
)
+ elsif Feature.enabled?(:environment_metrics_show_multiple_dashboards, project)
+ result = dashboard_finder.find(
+ project,
+ current_user,
+ environment,
+ dashboard_path: params[:dashboard]
+ )
- unless params[:embedded]
- result[:all_dashboards] = dashboard_finder.find_all_paths(project)
- end
+ result[:all_dashboards] = dashboard_finder.find_all_paths(project)
else
result = dashboard_finder.find(project, current_user, environment)
end
diff --git a/app/graphql/mutations/award_emojis/base.rb b/app/graphql/mutations/award_emojis/base.rb
index d868db84f9d..583744c3884 100644
--- a/app/graphql/mutations/award_emojis/base.rb
+++ b/app/graphql/mutations/award_emojis/base.rb
@@ -3,8 +3,6 @@
module Mutations
module AwardEmojis
class Base < BaseMutation
- include Gitlab::Graphql::Authorize::AuthorizeResource
-
authorize :award_emoji
argument :awardable_id,
diff --git a/app/graphql/mutations/base_mutation.rb b/app/graphql/mutations/base_mutation.rb
index 08d2a1f18a3..7273a74cb86 100644
--- a/app/graphql/mutations/base_mutation.rb
+++ b/app/graphql/mutations/base_mutation.rb
@@ -2,6 +2,7 @@
module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation
+ prepend Gitlab::Graphql::Authorize::AuthorizeResource
prepend Gitlab::Graphql::CopyFieldDescription
field :errors, [GraphQL::STRING_TYPE],
diff --git a/app/graphql/mutations/merge_requests/base.rb b/app/graphql/mutations/merge_requests/base.rb
index e85d16fc2c5..28e0cdc8cc7 100644
--- a/app/graphql/mutations/merge_requests/base.rb
+++ b/app/graphql/mutations/merge_requests/base.rb
@@ -3,7 +3,6 @@
module Mutations
module MergeRequests
class Base < BaseMutation
- include Gitlab::Graphql::Authorize::AuthorizeResource
include Mutations::ResolvesProject
argument :project_path, GraphQL::ID_TYPE,
diff --git a/app/graphql/mutations/notes/base.rb b/app/graphql/mutations/notes/base.rb
index a7198f5fba6..31dabc0a660 100644
--- a/app/graphql/mutations/notes/base.rb
+++ b/app/graphql/mutations/notes/base.rb
@@ -3,8 +3,6 @@
module Mutations
module Notes
class Base < BaseMutation
- include Gitlab::Graphql::Authorize::AuthorizeResource
-
field :note,
Types::Notes::NoteType,
null: true,
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 0d6a6496993..4b0713001a1 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -18,7 +18,16 @@ module BlobHelper
end
def ide_edit_path(project = @project, ref = @ref, path = @path, options = {})
- segments = [ide_path, 'project', project.full_path, 'edit', ref]
+ project_path =
+ if !current_user || can?(current_user, :push_code, project)
+ project.full_path
+ else
+ # We currently always fork to the user's namespace
+ # in edit_fork_button_tag
+ "#{current_user.namespace.full_path}/#{project.path}"
+ end
+
+ segments = [ide_path, 'project', project_path, 'edit', ref]
segments.concat(['-', encode_ide_path(path)]) if path.present?
File.join(segments)
end
diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb
index 8ef68018d23..bbe05f40999 100644
--- a/app/helpers/boards_helper.rb
+++ b/app/helpers/boards_helper.rb
@@ -99,7 +99,11 @@ module BoardsHelper
recent_project_boards_path(@project) if current_board_parent.is_a?(Project)
end
+ def serializer
+ CurrentBoardSerializer.new
+ end
+
def current_board_json
- board.to_json
+ serializer.represent(board).as_json
end
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 4e11772b252..4f73270577f 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -122,27 +122,30 @@ module IconsHelper
icon_class = 'file-pdf-o'
when '.jpg', '.jpeg', '.jif', '.jfif',
'.jp2', '.jpx', '.j2k', '.j2c',
- '.png', '.gif', '.tif', '.tiff',
- '.svg', '.ico', '.bmp'
+ '.apng', '.png', '.gif', '.tif', '.tiff',
+ '.svg', '.ico', '.bmp', '.webp'
icon_class = 'file-image-o'
- when '.zip', '.zipx', '.tar', '.gz', '.bz', '.bzip',
- '.xz', '.rar', '.7z'
+ when '.zip', '.zipx', '.tar', '.gz', '.gzip', '.tgz', '.bz', '.bzip',
+ '.bz2', '.bzip2', '.car', '.tbz', '.xz', 'txz', '.rar', '.7z',
+ '.lz', '.lzma', '.tlz'
icon_class = 'file-archive-o'
- when '.mp3', '.wma', '.ogg', '.oga', '.wav', '.flac', '.aac'
+ when '.mp3', '.wma', '.ogg', '.oga', '.wav', '.flac', '.aac', '.3ga',
+ '.ac3', '.midi', '.m4a', '.ape', '.mpa'
icon_class = 'file-audio-o'
when '.mp4', '.m4p', '.m4v',
'.mpg', '.mp2', '.mpeg', '.mpe', '.mpv',
- '.mpg', '.mpeg', '.m2v',
+ '.mpg', '.mpeg', '.m2v', '.m2ts',
'.avi', '.mkv', '.flv', '.ogv', '.mov',
'.3gp', '.3g2'
icon_class = 'file-video-o'
- when '.doc', '.dot', '.docx', '.docm', '.dotx', '.dotm', '.docb'
+ when '.doc', '.dot', '.docx', '.docm', '.dotx', '.dotm', '.docb',
+ '.odt', '.ott', '.uot', '.rtf'
icon_class = 'file-word-o'
when '.xls', '.xlt', '.xlm', '.xlsx', '.xlsm', '.xltx', '.xltm',
- '.xlsb', '.xla', '.xlam', '.xll', '.xlw'
+ '.xlsb', '.xla', '.xlam', '.xll', '.xlw', '.ots', '.ods', '.uos'
icon_class = 'file-excel-o'
when '.ppt', '.pot', '.pps', '.pptx', '.pptm', '.potx', '.potm',
- '.ppam', '.ppsx', '.ppsm', '.sldx', '.sldm'
+ '.ppam', '.ppsx', '.ppsm', '.sldx', '.sldm', '.odp', '.otp', '.uop'
icon_class = 'file-powerpoint-o'
else
icon_class = 'file-text-o'
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 26692934456..d5e5b472115 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -31,22 +31,24 @@ module SortingHelper
end
def projects_sort_options_hash
- Feature.enabled?(:project_list_filter_bar) && !current_controller?('admin/projects') ? projects_sort_common_options_hash : old_projects_sort_options_hash
- end
+ use_old_sorting = Feature.disabled?(:project_list_filter_bar) || current_controller?('admin/projects')
- # TODO: Simplify these sorting options
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/60798
- # https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/11209#note_162234858
- def old_projects_sort_options_hash
options = {
sort_value_latest_activity => sort_title_latest_activity,
+ sort_value_recently_created => sort_title_created_date,
sort_value_name => sort_title_name,
- sort_value_oldest_activity => sort_title_oldest_activity,
- sort_value_oldest_created => sort_title_oldest_created,
- sort_value_recently_created => sort_title_recently_created,
- sort_value_stars_desc => sort_title_most_stars
+ sort_value_stars_desc => sort_title_stars
}
+ if use_old_sorting
+ options = options.merge({
+ sort_value_oldest_activity => sort_title_oldest_activity,
+ sort_value_oldest_created => sort_title_oldest_created,
+ sort_value_recently_created => sort_title_recently_created,
+ sort_value_stars_desc => sort_title_most_stars
+ })
+ end
+
if current_controller?('admin/projects')
options[sort_value_largest_repo] = sort_title_largest_repo
end
@@ -54,26 +56,14 @@ module SortingHelper
options
end
- def projects_sort_common_options_hash
- {
- sort_value_latest_activity => sort_title_latest_activity,
- sort_value_recently_created => sort_title_created_date,
- sort_value_name => sort_title_name,
- sort_value_stars_desc => sort_title_stars
- }
- end
-
def projects_sort_option_titles
- {
- sort_value_latest_activity => sort_title_latest_activity,
- sort_value_recently_created => sort_title_created_date,
- sort_value_name => sort_title_name,
- sort_value_stars_desc => sort_title_stars,
+ # Only used for the project filter search bar
+ projects_sort_options_hash.merge({
sort_value_oldest_activity => sort_title_latest_activity,
sort_value_oldest_created => sort_title_created_date,
sort_value_name_desc => sort_title_name,
sort_value_stars_asc => sort_title_stars
- }
+ })
end
def projects_reverse_sort_options_hash
@@ -210,47 +200,42 @@ module SortingHelper
sort_options_hash[sort_value]
end
- def issuable_sort_icon_suffix(sort_value)
+ def sort_direction_icon(sort_value)
case sort_value
when sort_value_milestone, sort_value_due_date, /_asc\z/
- 'lowest'
+ 'sort-lowest'
else
- 'highest'
+ 'sort-highest'
end
end
- # TODO: dedupicate issuable and project sort direction
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/60798
- def issuable_sort_direction_button(sort_value)
+ def sort_direction_button(reverse_url, reverse_sort, sort_value)
link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort'
- reverse_sort = issuable_reverse_sort_order_hash[sort_value]
+ icon = sort_direction_icon(sort_value)
+ url = reverse_url
- if reverse_sort
- reverse_url = page_filter_path(sort: reverse_sort)
- else
- reverse_url = '#'
+ unless reverse_sort
+ url = '#'
link_class += ' disabled'
end
- link_to(reverse_url, type: 'button', class: link_class, title: s_('SortOptions|Sort direction')) do
- sprite_icon("sort-#{issuable_sort_icon_suffix(sort_value)}", size: 16)
+ link_to(url, type: 'button', class: link_class, title: s_('SortOptions|Sort direction')) do
+ sprite_icon(icon, size: 16)
end
end
+ def issuable_sort_direction_button(sort_value)
+ reverse_sort = issuable_reverse_sort_order_hash[sort_value]
+ url = page_filter_path(sort: reverse_sort)
+
+ sort_direction_button(url, reverse_sort, sort_value)
+ end
+
def project_sort_direction_button(sort_value)
- link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort'
reverse_sort = projects_reverse_sort_options_hash[sort_value]
+ url = filter_projects_path(sort: reverse_sort)
- if reverse_sort
- reverse_url = filter_projects_path(sort: reverse_sort)
- else
- reverse_url = '#'
- link_class += ' disabled'
- end
-
- link_to(reverse_url, type: 'button', class: link_class, title: s_('SortOptions|Sort direction')) do
- sprite_icon("sort-#{issuable_sort_icon_suffix(sort_value)}", size: 16)
- end
+ sort_direction_button(url, reverse_sort, sort_value)
end
# Titles.
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index a3575462de0..bb1cdcb1b31 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -154,4 +154,36 @@ module TreeHelper
"logs-path" => logs_path
}
end
+
+ def breadcrumb_data_attributes
+ attrs = {
+ can_collaborate: can_collaborate_with_project?(@project).to_s,
+ new_blob_path: project_new_blob_path(@project, @id),
+ new_branch_path: new_project_branch_path(@project),
+ new_tag_path: new_project_tag_path(@project),
+ can_edit_tree: can_edit_tree?.to_s
+ }
+
+ if can?(current_user, :fork_project, @project) && can?(current_user, :create_merge_request_in, @project)
+ continue_param = {
+ to: project_new_blob_path(@project, @id),
+ notice: edit_in_new_fork_notice,
+ notice_now: edit_in_new_fork_notice_now
+ }
+
+ attrs.merge!(
+ fork_new_blob_path: project_forks_path(@project, namespace_key: current_user.namespace.id, continue: continue_param),
+ fork_new_directory_path: project_forks_path(@project, namespace_key: current_user.namespace.id, continue: continue_param.merge({
+ to: request.fullpath,
+ notice: _("%{edit_in_new_fork_notice} Try to create a new directory again.") % { edit_in_new_fork_notice: edit_in_new_fork_notice }
+ })),
+ fork_upload_blob_path: project_forks_path(@project, namespace_key: current_user.namespace.id, continue: continue_param.merge({
+ to: request.fullpath,
+ notice: _("%{edit_in_new_fork_notice} Try to upload a file again.") % { edit_in_new_fork_notice: edit_in_new_fork_notice }
+ }))
+ )
+ end
+
+ attrs
+ end
end
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index b318b27992a..2bd803c0177 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -65,20 +65,6 @@ module VisibilityLevelHelper
end
end
- def restricted_visibility_level_description(level)
- level_name = Gitlab::VisibilityLevel.level_name(level)
- _("%{level_name} visibility has been restricted by the administrator.") % { level_name: level_name.capitalize }
- end
-
- def disallowed_visibility_level_description(level, form_model)
- case form_model
- when Project
- disallowed_project_visibility_level_description(level, form_model)
- when Group
- disallowed_group_visibility_level_description(level, form_model)
- end
- end
-
# Note: these messages closely mirror the form validation strings found in the project
# model and any changes or additons to these may also need to be made there.
def disallowed_project_visibility_level_description(level, project)
@@ -181,6 +167,14 @@ module VisibilityLevelHelper
[requested_level, max_allowed_visibility_level(form_model)].min
end
+ def multiple_visibility_levels_restricted?
+ restricted_visibility_levels.many? # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ def all_visibility_levels_restricted?
+ Gitlab::VisibilityLevel.values == restricted_visibility_levels
+ end
+
private
def max_allowed_visibility_level(form_model)
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index ae7a1108841..635fcc86166 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -578,7 +578,7 @@ module Ci
end
def valid_token?(token)
- self.token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
+ self.token && ActiveSupport::SecurityUtils.secure_compare(token, self.token)
end
def has_tags?
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 20ca4a9ab24..2262282e647 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -196,7 +196,7 @@ module Ci
sql = 'CASE ci_pipelines.source WHEN (?) THEN 0 ELSE 1 END, ci_pipelines.id DESC'
query = ApplicationRecord.send(:sanitize_sql_array, [sql, sources[:merge_request_event]]) # rubocop:disable GitlabSecurity/PublicSend
- order(query)
+ order(Arel.sql(query))
end
scope :for_user, -> (user) { where(user: user) }
diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb
index ba8cea0cea9..42d4e86fe8d 100644
--- a/app/models/ci/pipeline_schedule.rb
+++ b/app/models/ci/pipeline_schedule.rb
@@ -4,11 +4,8 @@ module Ci
class PipelineSchedule < ApplicationRecord
extend Gitlab::Ci::Model
include Importable
- include IgnorableColumn
include StripAttribute
- ignore_column :deleted_at
-
belongs_to :project
belongs_to :owner, class_name: 'User'
has_one :last_pipeline, -> { order(id: :desc) }, class_name: 'Ci::Pipeline'
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index 8927bb9bc18..8792c5cf98b 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -3,17 +3,15 @@
module Ci
class Trigger < ApplicationRecord
extend Gitlab::Ci::Model
- include IgnorableColumn
include Presentable
- ignore_column :deleted_at
-
belongs_to :project
belongs_to :owner, class_name: "User"
has_many :trigger_requests
validates :token, presence: true, uniqueness: true
+ validates :owner, presence: true, unless: :supports_legacy_tokens?
before_validation :set_default_values
@@ -37,8 +35,13 @@ module Ci
self.owner_id.blank?
end
+ def supports_legacy_tokens?
+ Feature.enabled?(:use_legacy_pipeline_triggers, project)
+ end
+
def can_access_project?
- self.owner_id.blank? || Ability.allowed?(self.owner, :create_build, project)
+ supports_legacy_tokens? && legacy? ||
+ Ability.allowed?(self.owner, :create_build, project)
end
end
end
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index f0256ff4d41..6ae8c3bd7f3 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -29,13 +29,6 @@ module Clusters
content_values.to_yaml
end
- # Need to investigate if pipelines run by this runner will stop upon the
- # executor pod stopping
- # I.e.run a pipeline, and uninstall runner while pipeline is running
- def allowed_to_uninstall?
- false
- end
-
def install_command
Gitlab::Kubernetes::Helm::InstallCommand.new(
name: name,
@@ -47,6 +40,14 @@ module Clusters
)
end
+ def prepare_uninstall
+ runner&.update!(active: false)
+ end
+
+ def post_uninstall
+ runner.destroy!
+ end
+
private
def ensure_runner
diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb
index 4514498b84b..803a65726d3 100644
--- a/app/models/clusters/concerns/application_core.rb
+++ b/app/models/clusters/concerns/application_core.rb
@@ -46,6 +46,16 @@ module Clusters
command.version = version
end
end
+
+ def prepare_uninstall
+ # Override if your application needs any action before
+ # being uninstalled by Helm
+ end
+
+ def post_uninstall
+ # Override if your application needs any action after
+ # being uninstalled by Helm
+ end
end
end
end
diff --git a/app/models/clusters/concerns/application_status.rb b/app/models/clusters/concerns/application_status.rb
index 54a3dda6d75..342d766f723 100644
--- a/app/models/clusters/concerns/application_status.rb
+++ b/app/models/clusters/concerns/application_status.rb
@@ -59,29 +59,33 @@ module Clusters
transition [:scheduled] => :uninstalling
end
- before_transition any => [:scheduled] do |app_status, _|
- app_status.status_reason = nil
+ before_transition any => [:scheduled] do |application, _|
+ application.status_reason = nil
end
- before_transition any => [:errored] do |app_status, transition|
+ before_transition any => [:errored] do |application, transition|
status_reason = transition.args.first
- app_status.status_reason = status_reason if status_reason
+ application.status_reason = status_reason if status_reason
end
- before_transition any => [:updating] do |app_status, _|
- app_status.status_reason = nil
+ before_transition any => [:updating] do |application, _|
+ application.status_reason = nil
end
- before_transition any => [:update_errored, :uninstall_errored] do |app_status, transition|
+ before_transition any => [:update_errored, :uninstall_errored] do |application, transition|
status_reason = transition.args.first
- app_status.status_reason = status_reason if status_reason
+ application.status_reason = status_reason if status_reason
end
- before_transition any => [:installed, :updated] do |app_status, _|
+ before_transition any => [:installed, :updated] do |application, _|
# When installing any application we are also performing an update
# of tiller (see Gitlab::Kubernetes::Helm::ClientCommand) so
# therefore we need to reflect that in the database.
- app_status.cluster.application_helm.update!(version: Gitlab::Kubernetes::Helm::HELM_VERSION)
+ application.cluster.application_helm.update!(version: Gitlab::Kubernetes::Helm::HELM_VERSION)
+ end
+
+ after_transition any => [:uninstalling], :use_transactions => false do |application, _|
+ application.prepare_uninstall
end
end
end
diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb
index 78bcce2f592..27a5c3d5286 100644
--- a/app/models/concerns/has_status.rb
+++ b/app/models/concerns/has_status.rb
@@ -33,22 +33,24 @@ module HasStatus
canceled = scope_relevant.canceled.select('count(*)').to_sql
warnings = scope_warnings.select('count(*) > 0').to_sql.presence || 'false'
- "(CASE
- WHEN (#{builds})=(#{skipped}) AND (#{warnings}) THEN 'success'
- WHEN (#{builds})=(#{skipped}) THEN 'skipped'
- WHEN (#{builds})=(#{success}) THEN 'success'
- WHEN (#{builds})=(#{created}) THEN 'created'
- WHEN (#{builds})=(#{preparing}) THEN 'preparing'
- WHEN (#{builds})=(#{success})+(#{skipped}) THEN 'success'
- WHEN (#{builds})=(#{success})+(#{skipped})+(#{canceled}) THEN 'canceled'
- WHEN (#{builds})=(#{created})+(#{skipped})+(#{pending}) THEN 'pending'
- WHEN (#{running})+(#{pending})>0 THEN 'running'
- WHEN (#{manual})>0 THEN 'manual'
- WHEN (#{scheduled})>0 THEN 'scheduled'
- WHEN (#{preparing})>0 THEN 'preparing'
- WHEN (#{created})>0 THEN 'running'
- ELSE 'failed'
- END)"
+ Arel.sql(
+ "(CASE
+ WHEN (#{builds})=(#{skipped}) AND (#{warnings}) THEN 'success'
+ WHEN (#{builds})=(#{skipped}) THEN 'skipped'
+ WHEN (#{builds})=(#{success}) THEN 'success'
+ WHEN (#{builds})=(#{created}) THEN 'created'
+ WHEN (#{builds})=(#{preparing}) THEN 'preparing'
+ WHEN (#{builds})=(#{success})+(#{skipped}) THEN 'success'
+ WHEN (#{builds})=(#{success})+(#{skipped})+(#{canceled}) THEN 'canceled'
+ WHEN (#{builds})=(#{created})+(#{skipped})+(#{pending}) THEN 'pending'
+ WHEN (#{running})+(#{pending})>0 THEN 'running'
+ WHEN (#{manual})>0 THEN 'manual'
+ WHEN (#{scheduled})>0 THEN 'scheduled'
+ WHEN (#{preparing})>0 THEN 'preparing'
+ WHEN (#{created})>0 THEN 'running'
+ ELSE 'failed'
+ END)"
+ )
end
def status
@@ -88,22 +90,22 @@ module HasStatus
state :scheduled, value: 'scheduled'
end
- scope :created, -> { where(status: 'created') }
- scope :preparing, -> { where(status: 'preparing') }
- scope :relevant, -> { where(status: AVAILABLE_STATUSES - ['created']) }
- scope :running, -> { where(status: 'running') }
- scope :pending, -> { where(status: 'pending') }
- scope :success, -> { where(status: 'success') }
- scope :failed, -> { where(status: 'failed') }
- scope :canceled, -> { where(status: 'canceled') }
- scope :skipped, -> { where(status: 'skipped') }
- scope :manual, -> { where(status: 'manual') }
- scope :scheduled, -> { where(status: 'scheduled') }
- scope :alive, -> { where(status: [:created, :preparing, :pending, :running]) }
- scope :created_or_pending, -> { where(status: [:created, :pending]) }
- scope :running_or_pending, -> { where(status: [:running, :pending]) }
- scope :finished, -> { where(status: [:success, :failed, :canceled]) }
- scope :failed_or_canceled, -> { where(status: [:failed, :canceled]) }
+ scope :created, -> { with_status(:created) }
+ scope :preparing, -> { with_status(:preparing) }
+ scope :relevant, -> { without_status(:created) }
+ scope :running, -> { with_status(:running) }
+ scope :pending, -> { with_status(:pending) }
+ scope :success, -> { with_status(:success) }
+ scope :failed, -> { with_status(:failed) }
+ scope :canceled, -> { with_status(:canceled) }
+ scope :skipped, -> { with_status(:skipped) }
+ scope :manual, -> { with_status(:manual) }
+ scope :scheduled, -> { with_status(:scheduled) }
+ scope :alive, -> { with_status(:created, :preparing, :pending, :running) }
+ scope :created_or_pending, -> { with_status(:created, :pending) }
+ scope :running_or_pending, -> { with_status(:running, :pending) }
+ scope :finished, -> { with_status(:success, :failed, :canceled) }
+ scope :failed_or_canceled, -> { with_status(:failed, :canceled) }
scope :cancelable, -> do
where(status: [:running, :preparing, :pending, :created, :scheduled])
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb
index 22b6b1d720c..e4fe46d722a 100644
--- a/app/models/concerns/relative_positioning.rb
+++ b/app/models/concerns/relative_positioning.rb
@@ -179,7 +179,7 @@ module RelativePositioning
relation = yield relation if block_given?
relation
- .pluck(self.class.parent_column, "#{calculation}(relative_position) AS position")
+ .pluck(self.class.parent_column, Arel.sql("#{calculation}(relative_position) AS position"))
.first&.
last
end
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index b9ffc64e4a9..9becab632f3 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -46,7 +46,7 @@ module Routable
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/18603. Also note that
# our unique index is case-sensitive in Postgres.
binary = Gitlab::Database.mysql? ? 'BINARY' : ''
- order_sql = "(CASE WHEN #{binary} routes.path = #{connection.quote(path)} THEN 0 ELSE 1 END)"
+ order_sql = Arel.sql("(CASE WHEN #{binary} routes.path = #{connection.quote(path)} THEN 0 ELSE 1 END)")
found = where_full_path_in([path]).reorder(order_sql).take
return found if found
diff --git a/app/models/concerns/stepable.rb b/app/models/concerns/stepable.rb
new file mode 100644
index 00000000000..d00a049a004
--- /dev/null
+++ b/app/models/concerns/stepable.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Stepable
+ extend ActiveSupport::Concern
+
+ def steps
+ self.class._all_steps
+ end
+
+ def execute_steps
+ initial_result = {}
+
+ steps.inject(initial_result) do |previous_result, callback|
+ result = method(callback).call
+
+ if result[:status] == :error
+ result[:failed_step] = callback
+
+ break result
+ end
+
+ previous_result.merge(result)
+ end
+ end
+
+ class_methods do
+ def _all_steps
+ @_all_steps ||= []
+ end
+
+ def steps(*methods)
+ _all_steps.concat methods
+ end
+ end
+end
diff --git a/app/models/concerns/token_authenticatable.rb b/app/models/concerns/token_authenticatable.rb
index 8c769be0489..1293df571a3 100644
--- a/app/models/concerns/token_authenticatable.rb
+++ b/app/models/concerns/token_authenticatable.rb
@@ -52,7 +52,7 @@ module TokenAuthenticatable
mod.define_method("#{token_field}_matches?") do |other_token|
token = read_attribute(token_field)
- token.present? && ActiveSupport::SecurityUtils.variable_size_secure_compare(other_token, token)
+ token.present? && ActiveSupport::SecurityUtils.secure_compare(other_token, token)
end
end
diff --git a/app/models/email.rb b/app/models/email.rb
index 0ddaa049c3b..580633d3232 100644
--- a/app/models/email.rb
+++ b/app/models/email.rb
@@ -4,9 +4,8 @@ class Email < ApplicationRecord
include Sortable
include Gitlab::SQL::Pattern
- belongs_to :user
+ belongs_to :user, optional: false
- validates :user_id, presence: true
validates :email, presence: true, uniqueness: true, devise_email: true
validate :unique_email, if: ->(email) { email.email_changed? }
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 982a94315bd..12d30389910 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -13,11 +13,8 @@ class Issue < ApplicationRecord
include RelativePositioning
include TimeTrackable
include ThrottledTouch
- include IgnorableColumn
include LabelEventable
- ignore_column :assignee_id, :branch_name, :deleted_at
-
DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
AnyDueDate = DueDateStruct.new('Any Due Date', '').freeze
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 53977748c30..68e6e48fb7d 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -7,7 +7,6 @@ class MergeRequest < ApplicationRecord
include Noteable
include Referable
include Presentable
- include IgnorableColumn
include TimeTrackable
include ManualInverseAssociation
include EachBatch
@@ -24,10 +23,6 @@ class MergeRequest < ApplicationRecord
SORTING_PREFERENCE_FIELD = :merge_requests_sort
- ignore_column :locked_at,
- :ref_fetched,
- :deleted_at
-
belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project"
belongs_to :merge_user, class_name: "User"
@@ -588,7 +583,11 @@ class MergeRequest < ApplicationRecord
end
def diff_refs
- persisted? ? merge_request_diff.diff_refs : repository_diff_refs
+ if importing? || persisted?
+ merge_request_diff.diff_refs
+ else
+ repository_diff_refs
+ end
end
# Instead trying to fetch the
diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb
index 22cedf57b86..5c53cfd8c27 100644
--- a/app/models/merge_requests_closing_issues.rb
+++ b/app/models/merge_requests_closing_issues.rb
@@ -25,7 +25,7 @@ class MergeRequestsClosingIssues < ApplicationRecord
class << self
def count_for_collection(ids, current_user)
- closing_merge_requests(ids, current_user).group(:issue_id).pluck('issue_id', 'COUNT(*) as count')
+ closing_merge_requests(ids, current_user).group(:issue_id).pluck('issue_id', Arel.sql('COUNT(*) as count'))
end
def count_for_issue(id, current_user)
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index af50293a179..b8d7348268a 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -8,13 +8,10 @@ class Namespace < ApplicationRecord
include AfterCommitQueue
include Storage::LegacyNamespace
include Gitlab::SQL::Pattern
- include IgnorableColumn
include FeatureGate
include FromUnion
include Gitlab::Utils::StrongMemoize
- ignore_column :deleted_at
-
# Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of
# Android repo (15) + some extra backup.
@@ -41,8 +38,7 @@ class Namespace < ApplicationRecord
validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
validates :name,
presence: true,
- length: { maximum: 255 },
- namespace_name: true
+ length: { maximum: 255 }
validates :description, length: { maximum: 255 }
validates :path,
@@ -264,6 +260,11 @@ class Namespace < ApplicationRecord
false
end
+ # Overridden in EE::Namespace
+ def feature_available?(_feature)
+ false
+ end
+
def full_path_before_last_save
if parent_id_before_last_save.nil?
path_before_last_save
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index d6d879c6d89..e6e491634ab 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -12,9 +12,11 @@ class PagesDomain < ApplicationRecord
validates :domain, hostname: { allow_numeric_hostname: true }
validates :domain, uniqueness: { case_sensitive: false }
- validates :certificate, presence: { message: 'must be present if HTTPS-only is enabled' }, if: ->(domain) { domain.project&.pages_https_only? }
+ validates :certificate, presence: { message: 'must be present if HTTPS-only is enabled' },
+ if: :certificate_should_be_present?
validates :certificate, certificate: true, if: ->(domain) { domain.certificate.present? }
- validates :key, presence: { message: 'must be present if HTTPS-only is enabled' }, if: ->(domain) { domain.project&.pages_https_only? }
+ validates :key, presence: { message: 'must be present if HTTPS-only is enabled' },
+ if: :certificate_should_be_present?
validates :key, certificate_key: true, if: ->(domain) { domain.key.present? }
validates :verification_code, presence: true, allow_blank: false
@@ -249,4 +251,8 @@ class PagesDomain < ApplicationRecord
rescue OpenSSL::PKey::PKeyError, OpenSSL::Cipher::CipherError
nil
end
+
+ def certificate_should_be_present?
+ !auto_ssl_enabled? && project&.pages_https_only?
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index a6e0b5722b6..2906aca75fc 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -31,7 +31,6 @@ class Project < ApplicationRecord
include FeatureGate
include OptionallySearch
include FromUnion
- include IgnorableColumn
extend Gitlab::Cache::RequestCache
extend Gitlab::ConfigHelper
@@ -56,8 +55,6 @@ class Project < ApplicationRecord
VALID_MIRROR_PORTS = [22, 80, 443].freeze
VALID_MIRROR_PROTOCOLS = %w(http https ssh git).freeze
- ignore_column :import_status, :import_jid, :import_error
-
cache_markdown_field :description, pipeline: :description
delegate :feature_available?, :builds_enabled?, :wiki_enabled?,
@@ -357,7 +354,7 @@ class Project < ApplicationRecord
scope :with_unmigrated_storage, -> { where('storage_version < :version OR storage_version IS NULL', version: LATEST_STORAGE_VERSION) }
# last_activity_at is throttled every minute, but last_repository_updated_at is updated with every push
- scope :sorted_by_activity, -> { reorder("GREATEST(COALESCE(last_activity_at, '1970-01-01'), COALESCE(last_repository_updated_at, '1970-01-01')) DESC") }
+ scope :sorted_by_activity, -> { reorder(Arel.sql("GREATEST(COALESCE(last_activity_at, '1970-01-01'), COALESCE(last_repository_updated_at, '1970-01-01')) DESC")) }
scope :sorted_by_stars_desc, -> { reorder(star_count: :desc) }
scope :sorted_by_stars_asc, -> { reorder(star_count: :asc) }
@@ -432,7 +429,7 @@ class Project < ApplicationRecord
numericality: { greater_than_or_equal_to: 10.minutes,
less_than: 1.month,
only_integer: true,
- message: _('needs to be beetween 10 minutes and 1 month') }
+ message: _('needs to be between 10 minutes and 1 month') }
# Used by Projects::CleanupService to hold a map of rewritten object IDs
mount_uploader :bfg_object_map, AttachmentUploader
@@ -612,7 +609,7 @@ class Project < ApplicationRecord
end
end
- def initialize(attributes = {})
+ def initialize(attributes = nil)
# We can't use default_value_for because the database has a default
# value of 0 for visibility_level. If someone attempts to create a
# private project, default_value_for will assume that the
@@ -622,6 +619,8 @@ class Project < ApplicationRecord
#
# To fix the problem, we assign the actual default in the application if
# no explicit visibility has been initialized.
+ attributes ||= {}
+
unless visibility_attribute_present?(attributes)
attributes[:visibility_level] = Gitlab::CurrentSettings.default_project_visibility
end
@@ -688,10 +687,6 @@ class Project < ApplicationRecord
{ scope: :project, status: auto_devops&.enabled || Feature.enabled?(:force_autodevops_on_by_default, self) }
end
- def multiple_mr_assignees_enabled?
- Feature.enabled?(:multiple_merge_request_assignees, self)
- end
-
def daily_statistics_enabled?
Feature.enabled?(:project_daily_statistics, self, default_enabled: true)
end
@@ -1557,7 +1552,7 @@ class Project < ApplicationRecord
end
def valid_runners_token?(token)
- self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token)
+ self.runners_token && ActiveSupport::SecurityUtils.secure_compare(token, self.runners_token)
end
# rubocop: disable CodeReuse/ServiceClass
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index f0ef2d925ab..47106d7bdbb 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -7,7 +7,7 @@ class CiService < Service
default_value_for :category, 'ci'
def valid_token?(token)
- self.respond_to?(:token) && self.token.present? && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
+ self.respond_to?(:token) && self.token.present? && ActiveSupport::SecurityUtils.secure_compare(token, self.token)
end
def self.supported_events
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index a3b89b2543a..e571700fd02 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -250,7 +250,7 @@ class JiraService < IssueTrackerService
end
log_info("Successfully posted", client_url: client_url)
- "SUCCESS: Successfully posted to http://jira.example.net."
+ "SUCCESS: Successfully posted to #{client_url}."
end
end
diff --git a/app/models/project_services/slash_commands_service.rb b/app/models/project_services/slash_commands_service.rb
index bfabc6d262c..5f5cff97808 100644
--- a/app/models/project_services/slash_commands_service.rb
+++ b/app/models/project_services/slash_commands_service.rb
@@ -12,7 +12,7 @@ class SlashCommandsService < Service
def valid_token?(token)
self.respond_to?(:token) &&
self.token.present? &&
- ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
+ ActiveSupport::SecurityUtils.secure_compare(token, self.token)
end
def self.supported_events
diff --git a/app/models/user.rb b/app/models/user.rb
index 26be197209a..0fd3daa3383 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -185,6 +185,7 @@ class User < ApplicationRecord
before_validation :set_notification_email, if: :new_record?
before_validation :set_public_email, if: :public_email_changed?
before_validation :set_commit_email, if: :commit_email_changed?
+ before_save :default_private_profile_to_false
before_save :set_public_email, if: :public_email_changed? # in case validation is skipped
before_save :set_commit_email, if: :commit_email_changed? # in case validation is skipped
before_save :ensure_incoming_email_token
@@ -1117,9 +1118,10 @@ class User < ApplicationRecord
def ensure_namespace_correct
if namespace
- namespace.path = namespace.name = username if username_changed?
+ namespace.path = username if username_changed?
+ namespace.name = name if name_changed?
else
- build_namespace(path: username, name: username)
+ build_namespace(path: username, name: name)
end
end
@@ -1490,6 +1492,12 @@ class User < ApplicationRecord
private
+ def default_private_profile_to_false
+ return unless private_profile_changed? && private_profile.nil?
+
+ self.private_profile = false
+ end
+
def has_current_license?
false
end
diff --git a/app/policies/ci/trigger_policy.rb b/app/policies/ci/trigger_policy.rb
index 209db44539c..578301d7f7e 100644
--- a/app/policies/ci/trigger_policy.rb
+++ b/app/policies/ci/trigger_policy.rb
@@ -5,7 +5,7 @@ module Ci
delegate { @subject.project }
with_options scope: :subject, score: 0
- condition(:legacy) { @subject.legacy? }
+ condition(:legacy) { @subject.supports_legacy_tokens? && @subject.legacy? }
with_score 0
condition(:is_owner) { @user && @subject.owner_id == @user.id }
diff --git a/app/policies/clusters/instance_policy.rb b/app/policies/clusters/instance_policy.rb
index f72096e8fc6..bd7ff413afe 100644
--- a/app/policies/clusters/instance_policy.rb
+++ b/app/policies/clusters/instance_policy.rb
@@ -2,11 +2,6 @@
module Clusters
class InstancePolicy < BasePolicy
- include ClusterableActions
-
- condition(:has_clusters, scope: :subject) { clusterable_has_clusters? }
- condition(:can_have_multiple_clusters) { multiple_clusters_available? }
-
rule { admin }.policy do
enable :read_cluster
enable :add_cluster
@@ -14,7 +9,5 @@ module Clusters
enable :update_cluster
enable :admin_cluster
end
-
- rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster
end
end
diff --git a/app/policies/concerns/clusterable_actions.rb b/app/policies/concerns/clusterable_actions.rb
deleted file mode 100644
index 08ddd742ea9..00000000000
--- a/app/policies/concerns/clusterable_actions.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module ClusterableActions
- private
-
- # Overridden on EE module
- def multiple_clusters_available?
- false
- end
-
- def clusterable_has_clusters?
- !subject.clusters.empty?
- end
-end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index ea86858181d..9219283992f 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
class GroupPolicy < BasePolicy
- include ClusterableActions
-
desc "Group is public"
with_options scope: :subject, score: 0
condition(:public_group) { @subject.public? }
@@ -29,9 +27,6 @@ class GroupPolicy < BasePolicy
GroupProjectsFinder.new(group: @subject, current_user: @user, options: { include_subgroups: true, only_owned: true }).execute.any?
end
- condition(:has_clusters, scope: :subject) { clusterable_has_clusters? }
- condition(:can_have_multiple_clusters) { multiple_clusters_available? }
-
with_options scope: :subject, score: 0
condition(:request_access_enabled) { @subject.request_access_enabled }
@@ -121,8 +116,6 @@ class GroupPolicy < BasePolicy
rule { owner & (~share_with_group_locked | ~has_parent | ~parent_share_with_group_locked | can_change_parent_share_with_group_lock) }.enable :change_share_with_group_lock
- rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster
-
rule { developer & developer_maintainer_access }.enable :create_projects
rule { create_projects_disabled }.prevent :create_projects
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 3c9ffbb2065..e79bac6bee3 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -2,7 +2,6 @@
class ProjectPolicy < BasePolicy
extend ClassMethods
- include ClusterableActions
READONLY_FEATURES_WHEN_ARCHIVED = %i[
issue
@@ -114,9 +113,6 @@ class ProjectPolicy < BasePolicy
@subject.feature_available?(:merge_requests, @user)
end
- condition(:has_clusters, scope: :subject) { clusterable_has_clusters? }
- condition(:can_have_multiple_clusters) { multiple_clusters_available? }
-
condition(:internal_builds_disabled) do
!@subject.builds_enabled?
end
@@ -430,8 +426,6 @@ class ProjectPolicy < BasePolicy
(~guest & can?(:read_project_for_iids) & merge_requests_visible_to_user) | can?(:read_merge_request)
end.enable :read_merge_request_iid
- rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster
-
rule { ~can?(:read_cross_project) & ~classification_label_authorized }.policy do
# Preventing access here still allows the projects to be listed. Listing
# projects doesn't check the `:read_project` ability. But instead counts
diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb
index 34bdf156623..fff6d23efdf 100644
--- a/app/presenters/clusterable_presenter.rb
+++ b/app/presenters/clusterable_presenter.rb
@@ -13,7 +13,8 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
end
def can_add_cluster?
- can?(current_user, :add_cluster, clusterable)
+ can?(current_user, :add_cluster, clusterable) &&
+ (has_no_clusters? || multiple_clusters_available?)
end
def can_create_cluster?
@@ -63,4 +64,15 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
def learn_more_link
raise NotImplementedError
end
+
+ private
+
+ # Overridden on EE module
+ def multiple_clusters_available?
+ false
+ end
+
+ def has_no_clusters?
+ clusterable.clusters.empty?
+ end
end
diff --git a/app/serializers/current_board_entity.rb b/app/serializers/current_board_entity.rb
new file mode 100644
index 00000000000..371151532f8
--- /dev/null
+++ b/app/serializers/current_board_entity.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class CurrentBoardEntity < Grape::Entity
+ expose :id
+ expose :name
+end
diff --git a/app/serializers/current_board_serializer.rb b/app/serializers/current_board_serializer.rb
new file mode 100644
index 00000000000..c58c77194f2
--- /dev/null
+++ b/app/serializers/current_board_serializer.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class CurrentBoardSerializer < BaseSerializer
+ entity CurrentBoardEntity
+end
diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb
index 201048aaba5..73f3408a240 100644
--- a/app/services/audit_event_service.rb
+++ b/app/services/audit_event_service.rb
@@ -35,8 +35,12 @@ class AuditEventService
@file_logger ||= Gitlab::AuditJsonLogger.build
end
+ def formatted_details
+ @details.merge(@details.slice(:from, :to).transform_values(&:to_s))
+ end
+
def log_security_event_to_file
- file_logger.info(base_payload.merge(@details))
+ file_logger.info(base_payload.merge(formatted_details))
end
def log_security_event_to_database
diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb
index 755d723b9a0..00ce27db7c8 100644
--- a/app/services/boards/issues/move_service.rb
+++ b/app/services/boards/issues/move_service.rb
@@ -11,26 +11,51 @@ module Boards
end
def execute_multiple(issues)
- return false if issues.empty?
+ return execute_multiple_empty_result if issues.empty?
+ handled_issues = []
last_inserted_issue_id = nil
- issues.map do |issue|
+ count = issues.each.inject(0) do |moved_count, issue|
issue_modification_params = issue_params(issue)
- next if issue_modification_params.empty?
+ next moved_count if issue_modification_params.empty?
if last_inserted_issue_id
- issue_modification_params[:move_between_ids] = move_between_ids({ move_after_id: nil, move_before_id: last_inserted_issue_id })
+ issue_modification_params[:move_between_ids] = move_below(last_inserted_issue_id)
end
last_inserted_issue_id = issue.id
- move_single_issue(issue, issue_modification_params)
- end.all?
+ handled_issue = move_single_issue(issue, issue_modification_params)
+ handled_issues << present_issue_entity(handled_issue) if handled_issue
+ handled_issue && handled_issue.valid? ? moved_count + 1 : moved_count
+ end
+
+ {
+ count: count,
+ success: count == issues.size,
+ issues: handled_issues
+ }
end
private
+ def present_issue_entity(issue)
+ ::API::Entities::Issue.represent(issue)
+ end
+
+ def execute_multiple_empty_result
+ @execute_multiple_empty_result ||= {
+ count: 0,
+ success: false,
+ issues: []
+ }
+ end
+
+ def move_below(id)
+ move_between_ids({ move_after_id: nil, move_before_id: id })
+ end
+
def move_single_issue(issue, issue_modification_params)
- return false unless can?(current_user, :update_issue, issue)
+ return unless can?(current_user, :update_issue, issue)
update(issue, issue_modification_params)
end
diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb
index 4a7ce00b8e2..aaf56048b5c 100644
--- a/app/services/ci/process_pipeline_service.rb
+++ b/app/services/ci/process_pipeline_service.rb
@@ -44,7 +44,7 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def stage_indexes_of_created_processables
- created_processables.order(:stage_idx).pluck('distinct stage_idx')
+ created_processables.order(:stage_idx).pluck(Arel.sql('DISTINCT stage_idx'))
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -68,7 +68,7 @@ module Ci
latest_statuses = pipeline.statuses.latest
.group(:name)
.having('count(*) > 1')
- .pluck('max(id)', 'name')
+ .pluck(Arel.sql('MAX(id)'), 'name')
# mark builds that are retried
pipeline.statuses.latest
diff --git a/app/services/clusters/applications/check_uninstall_progress_service.rb b/app/services/clusters/applications/check_uninstall_progress_service.rb
index 8786d295d6a..e51d84ef052 100644
--- a/app/services/clusters/applications/check_uninstall_progress_service.rb
+++ b/app/services/clusters/applications/check_uninstall_progress_service.rb
@@ -23,6 +23,7 @@ module Clusters
private
def on_success
+ app.post_uninstall
app.destroy!
rescue StandardError => e
app.make_errored!(_('Application uninstalled but failed to destroy: %{error_message}') % { error_message: e.message })
diff --git a/app/services/clusters/create_service.rb b/app/services/clusters/create_service.rb
index 886e484caaf..5fb5e15c32d 100644
--- a/app/services/clusters/create_service.rb
+++ b/app/services/clusters/create_service.rb
@@ -10,24 +10,27 @@ module Clusters
def execute(access_token: nil)
raise ArgumentError, 'Unknown clusterable provided' unless clusterable
- raise ArgumentError, _('Instance does not support multiple Kubernetes clusters') unless can_create_cluster?
cluster_params = params.merge(user: current_user).merge(clusterable_params)
cluster_params[:provider_gcp_attributes].try do |provider|
provider[:access_token] = access_token
end
- create_cluster(cluster_params).tap do |cluster|
- ClusterProvisionWorker.perform_async(cluster.id) if cluster.persisted?
+ cluster = Clusters::Cluster.new(cluster_params)
+
+ unless can_create_cluster?
+ cluster.errors.add(:base, _('Instance does not support multiple Kubernetes clusters'))
end
- end
- private
+ return cluster if cluster.errors.present?
- def create_cluster(cluster_params)
- Clusters::Cluster.create(cluster_params)
+ cluster.tap do |cluster|
+ cluster.save && ClusterProvisionWorker.perform_async(cluster.id)
+ end
end
+ private
+
def clusterable
@clusterable ||= params.delete(:clusterable)
end
diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb
index e9659f5489a..e78e5d5fc2c 100644
--- a/app/services/groups/create_service.rb
+++ b/app/services/groups/create_service.rb
@@ -27,8 +27,7 @@ module Groups
@group.build_chat_team(name: response['name'], team_id: response['id'])
end
- @group.save
- @group.add_owner(current_user)
+ @group.add_owner(current_user) if @group.save
@group
end
diff --git a/app/services/issuable/clone/content_rewriter.rb b/app/services/issuable/clone/content_rewriter.rb
index 00d7078859d..f75b51c4be3 100644
--- a/app/services/issuable/clone/content_rewriter.rb
+++ b/app/services/issuable/clone/content_rewriter.rb
@@ -23,10 +23,14 @@ module Issuable
end
def rewrite_notes
+ new_discussion_ids = {}
original_entity.notes_with_associations.find_each do |note|
new_note = note.dup
+ new_discussion_ids[note.discussion_id] ||= Discussion.discussion_id(new_note)
new_params = {
- project: new_entity.project, noteable: new_entity,
+ project: new_entity.project,
+ noteable: new_entity,
+ discussion_id: new_discussion_ids[note.discussion_id],
note: rewrite_content(new_note.note),
note_html: nil,
created_at: note.created_at,
diff --git a/app/services/self_monitoring/project/create_service.rb b/app/services/self_monitoring/project/create_service.rb
new file mode 100644
index 00000000000..e5ef8c15456
--- /dev/null
+++ b/app/services/self_monitoring/project/create_service.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+module SelfMonitoring
+ module Project
+ class CreateService < ::BaseService
+ include Stepable
+
+ DEFAULT_VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
+ DEFAULT_NAME = 'GitLab Instance Administration'
+ DEFAULT_DESCRIPTION = <<~HEREDOC
+ This project is automatically generated and will be used to help monitor this GitLab instance.
+ HEREDOC
+
+ steps :validate_admins,
+ :create_project,
+ :add_project_members,
+ :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_project
+ admin_user = project_owner
+ @project = ::Projects::CreateService.new(admin_user, create_project_params).execute
+
+ if project.persisted?
+ success(project: project)
+ else
+ log_error("Could not create self-monitoring project. Errors: #{project.errors.full_messages}")
+ error('Could not create project')
+ end
+ end
+
+ def add_project_members
+ members = project.add_users(project_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_prometheus_manual_configuration
+ return success unless prometheus_enabled?
+ return success unless prometheus_listen_address.present?
+
+ # TODO: Currently, adding the internal prometheus server as a manual configuration
+ # is only possible if the setting to allow webhooks and services to connect
+ # to local network is on.
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/44496 will add
+ # a whitelist that will allow connections to certain ips on the local network.
+
+ 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 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 project_owner
+ instance_admins.first
+ end
+
+ def project_maintainers
+ # Exclude the first so that the project_owner is not added again as a member.
+ instance_admins - [project_owner]
+ end
+
+ def create_project_params
+ {
+ initialize_with_readme: true,
+ visibility_level: DEFAULT_VISIBILITY_LEVEL,
+ name: DEFAULT_NAME,
+ description: DEFAULT_DESCRIPTION
+ }
+ 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/validators/namespace_name_validator.rb b/app/validators/namespace_name_validator.rb
deleted file mode 100644
index fb1c241037c..00000000000
--- a/app/validators/namespace_name_validator.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-# NamespaceNameValidator
-#
-# Custom validator for GitLab namespace name strings.
-class NamespaceNameValidator < ActiveModel::EachValidator
- def validate_each(record, attribute, value)
- unless value =~ Gitlab::Regex.namespace_name_regex
- record.errors.add(attribute, Gitlab::Regex.namespace_name_regex_message)
- end
- end
-end
diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml
index d7d709ffd62..1282a032f52 100644
--- a/app/views/admin/application_settings/_pages.html.haml
+++ b/app/views/admin/application_settings/_pages.html.haml
@@ -14,23 +14,22 @@
= _("Require users to prove ownership of custom domains")
.form-text.text-muted
= _("Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled")
- = link_to icon('question-circle'), help_page_path('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
- - if Feature.enabled?(:pages_auto_ssl)
- %h5
- = _("Configure Let's Encrypt")
- %p
- - lets_encrypt_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: "https://letsencrypt.org/" }
- = _("%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA), that give digital certificates in order to enable HTTPS (SSL/TLS) for websites.").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: '</a>'.html_safe }
- .form-group
- = f.label :lets_encrypt_notification_email, _("Email"), class: 'label-bold'
- = f.text_field :lets_encrypt_notification_email, class: 'form-control'
- .form-text.text-muted
- = _("A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates.")
- .form-group
- .form-check
- = f.check_box :lets_encrypt_terms_of_service_accepted, class: 'form-check-input'
- = f.label :lets_encrypt_terms_of_service_accepted, class: 'form-check-label' do
- - terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path }
- = _("I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end}").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe }
+ = link_to icon('question-circle'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership')
+ %h5
+ = _("Configure Let's Encrypt")
+ %p
+ - lets_encrypt_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: "https://letsencrypt.org/" }
+ = _("%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA), that give digital certificates in order to enable HTTPS (SSL/TLS) for websites.").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: '</a>'.html_safe }
+ .form-group
+ = f.label :lets_encrypt_notification_email, _("Email"), class: 'label-bold'
+ = f.text_field :lets_encrypt_notification_email, class: 'form-control'
+ .form-text.text-muted
+ = _("A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates.")
+ .form-group
+ .form-check
+ = f.check_box :lets_encrypt_terms_of_service_accepted, class: 'form-check-input'
+ = f.label :lets_encrypt_terms_of_service_accepted, class: 'form-check-label' do
+ - terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path }
+ = _("I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end}").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe }
= f.submit _('Save changes'), class: "btn btn-success"
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
index 7dacd0b1d72..2f10f08c839 100644
--- a/app/views/devise/sessions/_new_base.html.haml
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -1,10 +1,10 @@
= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user gl-show-field-errors', 'aria-live' => 'assertive'}) do |f|
.form-group
= f.label "Username or email", for: "user_login", class: 'label-bold'
- = f.text_field :login, class: "form-control top qa-login-field", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required."
+ = f.text_field :login, class: "form-control top", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required.", data: { qa_selector: 'login_field' }
.form-group
= f.label :password, class: 'label-bold'
- = f.password_field :password, class: "form-control bottom qa-password-field", required: true, title: "This field is required."
+ = f.password_field :password, class: "form-control bottom", required: true, title: "This field is required.", data: { qa_selector: 'password_field' }
- if devise_mapping.rememberable?
.remember-me
%label{ for: "user_remember_me" }
@@ -17,4 +17,4 @@
= recaptcha_tags
.submit-container.move-submit-down
- = f.submit "Sign in", class: "btn btn-success qa-sign-in-button"
+ = f.submit "Sign in", class: "btn btn-success", data: { qa_selector: 'sign_in_button' }
diff --git a/app/views/devise/shared/_tabs_normal.html.haml b/app/views/devise/shared/_tabs_normal.html.haml
index 4cd03be572f..ab8c22532fd 100644
--- a/app/views/devise/shared/_tabs_normal.html.haml
+++ b/app/views/devise/shared/_tabs_normal.html.haml
@@ -3,4 +3,4 @@
%a.nav-link.qa-sign-in-tab.active{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in
- if allow_signup?
%li.nav-item{ role: 'presentation' }
- %a.nav-link.qa-register-tab{ href: '#register-pane', data: { track_label: 'sign_in_register', track_property: 'sign_in', track_event: 'click_button', track_value: 'register', toggle: 'tab' }, role: 'tab' } Register
+ %a.nav-link.qa-register-tab{ href: '#register-pane', data: { track_label: 'sign_in_register', track_property: '', track_event: 'click_button', track_value: '', toggle: 'tab' }, role: 'tab' } Register
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index 50933c7d434..ed904c48ddb 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -33,7 +33,7 @@
.documentation-index.md
= markdown(@help_index)
.col-md-4
- .card
+ .card.links-card
.card-header
Quick help
%ul.content-list
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index a5f57f5893c..c62dce880c0 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -2,7 +2,7 @@
- group_data_attrs = { group_path: j(@group.path), name: j(@group.name), issues_path: issues_group_path(@group), mr_path: merge_requests_group_path(@group) }
- if @project && @project.persisted?
- project_data_attrs = { project_path: j(@project.path), name: j(@project.name), issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project), issues_disabled: !@project.issues_enabled? }
-.search.search-form{ data: { track_label: "navbar_search", track_event: "activate_form_input" } }
+.search.search-form{ data: { track_label: "navbar_search", track_event: "activate_form_input", track_value: "" } }
= form_tag search_path, method: :get, class: 'form-inline' do |f|
.search-input-container
.search-input-wrap
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index ff3410f6268..e9a4a068599 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -1,7 +1,7 @@
!!! 5
%html.devise-layout-html{ class: system_message_class }
= render "layouts/head"
- %body.ui-indigo.login-page.application.navless.qa-login-page{ data: { page: body_data_page } }
+ %body.ui-indigo.login-page.application.navless{ data: { page: body_data_page, qa_selector: 'login_page' } }
= header_message
.page-wrap
= render "layouts/header/empty"
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index f9ee6f42e23..89f99472270 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -5,7 +5,7 @@
- else
- search_path_url = search_path
-%header.navbar.navbar-gitlab.qa-navbar.navbar-expand-sm.js-navbar
+%header.navbar.navbar-gitlab.navbar-expand-sm.js-navbar{ data: { qa_selector: 'navbar' } }
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid
.header-content
@@ -64,7 +64,7 @@
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/help_dropdown'
- if header_link?(:user_dropdown)
- %li.nav-item.header-user.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown" } }
+ %li.nav-item.header-user.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown", track_value: "", qa_selector: 'user_menu' } }
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
= image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar"
= sprite_icon('angle-down', css_class: 'caret-down')
diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml
index 1d7a501e5c2..e28efb09be5 100644
--- a/app/views/layouts/header/_new_dropdown.haml
+++ b/app/views/layouts/header/_new_dropdown.haml
@@ -1,4 +1,4 @@
-%li.header-new.dropdown{ data: { track_label: "new_dropdown", track_event: "click_dropdown" } }
+%li.header-new.dropdown{ data: { track_label: "new_dropdown", track_event: "click_dropdown", track_value: "" } }
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip qa-new-menu-toggle", id: "js-onboarding-new-project-link", title: _("New..."), ref: 'tooltip', aria: { label: _("New...") }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static' } do
= sprite_icon('plus-square', size: 16)
= sprite_icon('angle-down', css_class: 'caret-down')
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 54028dc8554..cbe713b7468 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -2,7 +2,7 @@
-# https://gitlab.com/gitlab-org/gitlab-ce/issues/49713 for more information.
%ul.list-unstyled.navbar-sub-nav
- if dashboard_nav_link?(:projects)
- = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown", data: { track_label: "projects_dropdown", track_event: "click_dropdown" } }) do
+ = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown", data: { track_label: "projects_dropdown", track_event: "click_dropdown", track_value: "" } }) do
%button.btn{ type: 'button', data: { toggle: "dropdown" } }
= _('Projects')
= sprite_icon('angle-down', css_class: 'caret-down')
@@ -10,7 +10,7 @@
= render "layouts/nav/projects_dropdown/show"
- if dashboard_nav_link?(:groups)
- = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups qa-groups-dropdown", data: { track_label: "groups_dropdown", track_event: "click_dropdown" } }) do
+ = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups qa-groups-dropdown", data: { track_label: "groups_dropdown", track_event: "click_dropdown", track_value: "" } }) do
%button.btn{ type: 'button', data: { toggle: "dropdown" } }
= _('Groups')
= sprite_icon('angle-down', css_class: 'caret-down')
diff --git a/app/views/notify/pages_domain_disabled_email.html.haml b/app/views/notify/pages_domain_disabled_email.html.haml
index 224b79bfde8..44f85df97b9 100644
--- a/app/views/notify/pages_domain_disabled_email.html.haml
+++ b/app/views/notify/pages_domain_disabled_email.html.haml
@@ -8,6 +8,6 @@
Domain: #{link_to @domain.domain, project_pages_domain_url(@project, @domain)}
%p
If this domain has been disabled in error, please follow
- = link_to 'these instructions', help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+ = link_to 'these instructions', help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership')
to verify and re-enable your domain.
= render 'removal_notification'
diff --git a/app/views/notify/pages_domain_disabled_email.text.haml b/app/views/notify/pages_domain_disabled_email.text.haml
index 4e81b054b1f..5a0fcab72d4 100644
--- a/app/views/notify/pages_domain_disabled_email.text.haml
+++ b/app/views/notify/pages_domain_disabled_email.text.haml
@@ -7,7 +7,7 @@ Domain: #{@domain.domain} (#{project_pages_domain_url(@project, @domain)})
If this domain has been disabled in error, please follow these instructions
to verify and re-enable your domain:
-= help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+= help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: 'steps')
If you no longer wish to use this domain with GitLab Pages, please remove it
from your GitLab project and delete any related DNS records.
diff --git a/app/views/notify/pages_domain_enabled_email.html.haml b/app/views/notify/pages_domain_enabled_email.html.haml
index db09e503f65..103b17a87df 100644
--- a/app/views/notify/pages_domain_enabled_email.html.haml
+++ b/app/views/notify/pages_domain_enabled_email.html.haml
@@ -7,5 +7,5 @@
Domain: #{link_to @domain.domain, project_pages_domain_url(@project, @domain)}
%p
Please visit
- = link_to 'these instructions', help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+ = link_to 'these instructions', help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: 'steps')
for more information about custom domain verification.
diff --git a/app/views/notify/pages_domain_enabled_email.text.haml b/app/views/notify/pages_domain_enabled_email.text.haml
index 1ed1dbb8315..bf8d2ac767a 100644
--- a/app/views/notify/pages_domain_enabled_email.text.haml
+++ b/app/views/notify/pages_domain_enabled_email.text.haml
@@ -5,5 +5,5 @@ Project: #{@project.human_name} (#{project_url(@project)})
Domain: #{@domain.domain} (#{project_pages_domain_url(@project, @domain)})
Please visit
-= help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+= help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: 'steps')
for more information about custom domain verification.
diff --git a/app/views/notify/pages_domain_verification_failed_email.html.haml b/app/views/notify/pages_domain_verification_failed_email.html.haml
index 03b298f8e7c..a819b66f18e 100644
--- a/app/views/notify/pages_domain_verification_failed_email.html.haml
+++ b/app/views/notify/pages_domain_verification_failed_email.html.haml
@@ -10,6 +10,6 @@
Until then, you can view your content at #{link_to @domain.url, @domain.url}
%p
Please visit
- = link_to 'these instructions', help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+ = link_to 'these instructions', help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: 'steps')
for more information about custom domain verification.
= render 'removal_notification'
diff --git a/app/views/notify/pages_domain_verification_failed_email.text.haml b/app/views/notify/pages_domain_verification_failed_email.text.haml
index c14e0e0c24d..85aa2d7a503 100644
--- a/app/views/notify/pages_domain_verification_failed_email.text.haml
+++ b/app/views/notify/pages_domain_verification_failed_email.text.haml
@@ -7,7 +7,7 @@ Unless you take action, it will be disabled on *#{@domain.enabled_until.strftime
Until then, you can view your content at #{@domain.url}
Please visit
-= help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+= help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: 'steps')
for more information about custom domain verification.
If you no longer wish to use this domain with GitLab Pages, please remove it
diff --git a/app/views/notify/pages_domain_verification_succeeded_email.html.haml b/app/views/notify/pages_domain_verification_succeeded_email.html.haml
index 2ead3187b10..808b12948f9 100644
--- a/app/views/notify/pages_domain_verification_succeeded_email.html.haml
+++ b/app/views/notify/pages_domain_verification_succeeded_email.html.haml
@@ -9,5 +9,5 @@
content at #{link_to @domain.url, @domain.url}
%p
Please visit
- = link_to 'these instructions', help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+ = link_to 'these instructions', help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: 'steps')
for more information about custom domain verification.
diff --git a/app/views/notify/pages_domain_verification_succeeded_email.text.haml b/app/views/notify/pages_domain_verification_succeeded_email.text.haml
index e7cdbdee420..8d0694ef613 100644
--- a/app/views/notify/pages_domain_verification_succeeded_email.text.haml
+++ b/app/views/notify/pages_domain_verification_succeeded_email.text.haml
@@ -6,5 +6,5 @@ Domain: #{@domain.domain} (#{project_pages_domain_url(@project, @domain)})
No action is required on your part. You can view your content at #{@domain.url}
Please visit
-= help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+= help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: 'steps')
for more information about custom domain verification.
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
index 6763513f9ae..95fdad125a7 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -20,6 +20,9 @@
- if vue_file_list_enabled?
#js-tree-list{ data: { project_path: @project.full_path, project_short_path: @project.path, ref: ref, full_name: @project.name_with_namespace } }
+ - if can_edit_tree?
+ = render 'projects/blob/upload', title: _('Upload New File'), placeholder: _('Upload New File'), button_title: _('Upload file'), form_path: project_create_blob_path(@project, @id), method: :post
+ = render 'projects/blob/new_dir'
- if @tree.readme
= render "projects/tree/readme", readme: @tree.readme
- else
diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml
index 7541737f79c..5d88be0925e 100644
--- a/app/views/projects/_new_project_fields.html.haml
+++ b/app/views/projects/_new_project_fields.html.haml
@@ -54,7 +54,7 @@
.form-group.row.initialize-with-readme-setting
%div{ :class => "col-sm-12" }
.form-check
- = check_box_tag 'project[initialize_with_readme]', '1', false, class: 'form-check-input qa-initialize-with-readme-checkbox', data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "init_with_readme" }
+ = check_box_tag 'project[initialize_with_readme]', '1', false, class: 'form-check-input qa-initialize-with-readme-checkbox', data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "init_with_readme", track_value: "" }
= label_tag 'project[initialize_with_readme]', class: 'form-check-label' do
.option-title
%strong= s_('ProjectsNew|Initialize repository with a README')
@@ -62,4 +62,4 @@
= s_('ProjectsNew|Allows you to immediately clone this project’s repository. Skip this if you plan to push up an existing repository.')
= f.submit _('Create project'), class: "btn btn-success project-submit", data: { track_label: "#{track_label}", track_event: "click_button", track_property: "create_project", track_value: "" }
-= link_to _('Cancel'), dashboard_projects_path, class: 'btn btn-cancel', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "cancel" }
+= link_to _('Cancel'), dashboard_projects_path, class: 'btn btn-cancel', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "cancel", track_value: "" }
diff --git a/app/views/projects/issues/import_csv/_modal.html.haml b/app/views/projects/issues/import_csv/_modal.html.haml
index 86bc54786ad..fe4a4236896 100644
--- a/app/views/projects/issues/import_csv/_modal.html.haml
+++ b/app/views/projects/issues/import_csv/_modal.html.haml
@@ -20,5 +20,5 @@
= _('It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected.')
= _('The maximum file size allowed is %{size}.') % { size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) }
.modal-footer
- %button{ type: 'submit', class: 'btn btn-success', title: _('Import issues'), data: { track_label: "export_issues_csv", track_event: "click_button"} }
+ %button{ type: 'submit', class: 'btn btn-success', title: _('Import issues'), data: { track_label: "export_issues_csv", track_event: "click_button", track_value: ""} }
= _('Import issues')
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 33de0aa153b..fabe636b05c 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -32,15 +32,15 @@
.col-lg-9.js-toggle-container
%ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
%li.nav-item{ role: 'presentation' }
- %a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab', track_label: 'blank_project', track_event: "click_tab" }, role: 'tab' }
+ %a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab', track_label: 'blank_project', track_event: "click_tab", track_value: "" }, role: 'tab' }
%span.d-none.d-sm-block= s_('ProjectsNew|Blank project')
%span.d-block.d-sm-none= s_('ProjectsNew|Blank')
%li.nav-item{ role: 'presentation' }
- %a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab', track_label: 'create_from_template', track_event: "click_tab" }, role: 'tab' }
+ %a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab', track_label: 'create_from_template', track_event: "click_tab", track_value: "" }, role: 'tab' }
%span.d-none.d-sm-block.qa-project-create-from-template-tab= s_('ProjectsNew|Create from template')
%span.d-block.d-sm-none= s_('ProjectsNew|Template')
%li.nav-item{ role: 'presentation' }
- %a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab', track_label: 'import_project', track_event: "click_tab" }, role: 'tab' }
+ %a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab', track_label: 'import_project', track_event: "click_tab", track_value: "" }, role: 'tab' }
%span.d-none.d-sm-block= s_('ProjectsNew|Import project')
%span.d-block.d-sm-none= s_('ProjectsNew|Import')
= render_if_exists 'projects/new_ci_cd_only_project_tab', active_tab: active_tab
@@ -51,7 +51,7 @@
= render 'new_project_fields', f: f, project_name_id: "blank-project-name"
#create-from-template-pane.tab-pane.js-toggle-container.px-0.pb-0{ class: active_when(active_tab == 'template'), role: 'tabpanel' }
- .card-slim.m-4.p-4
+ .card.card-slim.m-4.p-4
%div
- contributing_templates_url = 'https://gitlab.com/gitlab-org/project-templates/contributing'
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: contributing_templates_url }
diff --git a/app/views/projects/pages_domains/_form.html.haml b/app/views/projects/pages_domains/_form.html.haml
index 5b657966909..0e5c65a2f72 100644
--- a/app/views/projects/pages_domains/_form.html.haml
+++ b/app/views/projects/pages_domains/_form.html.haml
@@ -11,7 +11,7 @@
- if Gitlab.config.pages.external_https
- - auto_ssl_available = ::Gitlab::LetsEncrypt.enabled?(@domain)
+ - auto_ssl_available = ::Gitlab::LetsEncrypt.enabled?
- auto_ssl_enabled = @domain.auto_ssl_enabled?
- auto_ssl_available_and_enabled = auto_ssl_available && auto_ssl_enabled
diff --git a/app/views/projects/pages_domains/_helper_text.html.haml b/app/views/projects/pages_domains/_helper_text.html.haml
index 5a79fefabfc..f29cb0609e6 100644
--- a/app/views/projects/pages_domains/_helper_text.html.haml
+++ b/app/views/projects/pages_domains/_helper_text.html.haml
@@ -1,9 +1,5 @@
-- docs_link_url = help_page_path("user/project/pages/getting_started_part_three.md", anchor: "adding-certificates-to-your-project")
+- docs_link_url = help_page_path("user/project/pages/custom_domains_ssl_tls_certification/index.md", anchor: "adding-an-ssltls-certificate-to-pages")
- docs_link_start = "<a href=\"%{docs_link_url}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-nowrap\">".html_safe % { docs_link_url: docs_link_url }
- docs_link_end = "</a>".html_safe
--# Hiding behind a feature flag to avoid any changes to this feature's implemention
--# when the :pages_auto_ssl feature flag is disabled. This check should be removed
--# once the :pages_auto_ssl feature flag is removed.
-- if Feature.enabled?(:pages_auto_ssl)
- %p= _("Learn more about adding certificates to your project by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}.").html_safe % { docs_link_url: docs_link_url, docs_link_start: docs_link_start, docs_link_end: docs_link_end }
+%p= _("Learn more about adding certificates to your project by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}.").html_safe % { docs_link_url: docs_link_url, docs_link_start: docs_link_start, docs_link_end: docs_link_end }
diff --git a/app/views/projects/pages_domains/show.html.haml b/app/views/projects/pages_domains/show.html.haml
index 82147568981..e9019175219 100644
--- a/app/views/projects/pages_domains/show.html.haml
+++ b/app/views/projects/pages_domains/show.html.haml
@@ -53,7 +53,7 @@
.input-group-append
= clipboard_button(target: '#domain_verification', class: 'btn-default d-none d-sm-block')
%p.form-text.text-muted
- - link_to_help = link_to(_('verify ownership'), help_page_path('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record'))
+ - link_to_help = link_to(_('verify ownership'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership'))
= _("To %{link_to_help} of your domain, add the above key to a TXT record within to your DNS configuration.").html_safe % { link_to_help: link_to_help }
%tr
diff --git a/app/views/projects/project_templates/_built_in_templates.html.haml b/app/views/projects/project_templates/_built_in_templates.html.haml
index 6159f1c3542..d1c09e83fd3 100644
--- a/app/views/projects/project_templates/_built_in_templates.html.haml
+++ b/app/views/projects/project_templates/_built_in_templates.html.haml
@@ -9,9 +9,9 @@
.text-muted
= template.description
.controls.d-flex.align-items-center
- %a.btn.btn-default.append-right-10{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "create_from_template", track_property: "template_preview", track_event: "click_button", track_value: template.name } }
+ %a.btn.btn-default.append-right-10{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } }
= _("Preview")
%label.btn.btn-success.template-button.choose-template.append-bottom-0{ for: template.name }
- %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "create_from_template", track_property: "template_use", track_event: "click_button" } }
+ %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } }
%span
= _("Use template")
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index 1d0bc588c9c..41cd044a5b0 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -11,7 +11,7 @@
- addtotree_toggle_attributes = { title: _("You can only add files when you are on a branch"), data: { container: 'body' }, class: 'disabled has-tooltip' }
- if vue_file_list_enabled?
- #js-repo-breadcrumb
+ #js-repo-breadcrumb{ data: breadcrumb_data_attributes }
- else
%ul.breadcrumb.repo-breadcrumb
%li.breadcrumb-item
diff --git a/app/views/projects/triggers/_content.html.haml b/app/views/projects/triggers/_content.html.haml
index 96a41aa066c..e686068657c 100644
--- a/app/views/projects/triggers/_content.html.haml
+++ b/app/views/projects/triggers/_content.html.haml
@@ -1,8 +1,9 @@
-%p.append-bottom-default
- Triggers with the
- %span.badge.badge-primary legacy
- label do not have an associated user and only have access to the current project.
- %br
- = succeed '.' do
- Learn more in the
- = link_to 'triggers documentation', help_page_path('ci/triggers/README'), target: '_blank'
+- if Feature.enabled?(:use_legacy_pipeline_triggers, @project)
+ %p.append-bottom-default
+ Triggers with the
+ %span.badge.badge-primary legacy
+ label do not have an associated user and only have access to the current project.
+ %br
+ = succeed '.' do
+ Learn more in the
+ = link_to 'triggers documentation', help_page_path('ci/triggers/README'), target: '_blank'
diff --git a/app/views/projects/triggers/_trigger.html.haml b/app/views/projects/triggers/_trigger.html.haml
index 6f6f1e5e0c5..31a598ccd5e 100644
--- a/app/views/projects/triggers/_trigger.html.haml
+++ b/app/views/projects/triggers/_trigger.html.haml
@@ -8,8 +8,11 @@
.label-container
- if trigger.legacy?
- %span.badge.badge-primary.has-tooltip{ title: "Trigger makes use of deprecated functionality" } legacy
- - if !trigger.can_access_project?
+ - if trigger.supports_legacy_tokens?
+ %span.badge.badge-primary.has-tooltip{ title: "Trigger makes use of deprecated functionality" } legacy
+ - else
+ %span.badge.badge-danger.has-tooltip{ title: "Trigger is invalid due to being a legacy trigger. We recommend replacing it with a new trigger" } invalid
+ - elsif !trigger.can_access_project?
%span.badge.badge-danger.has-tooltip{ title: "Trigger user has insufficient permissions to project" } invalid
%td
diff --git a/app/views/shared/_visibility_radios.html.haml b/app/views/shared/_visibility_radios.html.haml
index 9fc46afe177..82ffdc9cd13 100644
--- a/app/views/shared/_visibility_radios.html.haml
+++ b/app/views/shared/_visibility_radios.html.haml
@@ -1,17 +1,19 @@
- Gitlab::VisibilityLevel.values.each do |level|
- disallowed = disallowed_visibility_level?(form_model, level)
- restricted = restricted_visibility_levels.include?(level)
- - disabled = disallowed || restricted
- .form-check{ class: [('disabled' if disabled), ('restricted' if restricted)] }
- = form.radio_button model_method, level, checked: (selected_level == level), disabled: disabled, class: 'form-check-input', data: { track_label: "blank_project", track_event: "activate_form_input", track_property: "#{model_method}", track_value: "#{level}" }
+ - next if disallowed || restricted
+
+ .form-check
+ = form.radio_button model_method, level, checked: (selected_level == level), class: 'form-check-input', data: { track_label: "blank_project", track_event: "activate_form_input", track_property: "#{model_method}_#{level}", track_value: "" }
= form.label "#{model_method}_#{level}", class: 'form-check-label' do
= visibility_level_icon(level)
.option-title
= visibility_level_label(level)
.option-description
= visibility_level_description(level, form_model)
- .option-disabled-reason
- - if restricted
- = restricted_visibility_level_description(level)
- - elsif disallowed
- = disallowed_visibility_level_description(level, form_model)
+
+.text-muted
+ - if all_visibility_levels_restricted?
+ = _('Visibility settings have been disabled by the administrator.')
+ - elsif multiple_visibility_levels_restricted?
+ = _('Other visibility settings have been disabled by the administrator.')
diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml
index 813fccd217b..1be230eedb9 100644
--- a/app/views/shared/boards/_show.html.haml
+++ b/app/views/shared/boards/_show.html.haml
@@ -14,8 +14,7 @@
%script#js-board-promotion{ type: "text/x-template" }= render_if_exists "shared/promotions/promote_issue_board"
#board-app.boards-app.position-relative{ "v-cloak" => "true", data: board_data, ":class" => "{ 'is-compact': detailIssueVisible }" }
- .d-none.d-sm-none.d-md-block
- = render 'shared/issuable/search_bar', type: :boards, board: board
+ = render 'shared/issuable/search_bar', type: :boards, board: board
.boards-list.w-100.py-3.px-2.text-nowrap
.boards-app-loading.w-100.text-center{ "v-if" => "loading" }
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 3d6c5d29d44..a97ac5e2a2d 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -4,7 +4,7 @@
- user_can_admin_list = board && can?(current_user, :admin_list, board.parent)
.issues-filters{ class: ("w-100" if type == :boards_modal) }
- .issues-details-filters.filtered-search-block.d-flex{ class: block_css_class, "v-pre" => type == :boards_modal }
+ .issues-details-filters.filtered-search-block.d-flex.flex-column.flex-md-row{ class: block_css_class, "v-pre" => type == :boards_modal }
- if type == :boards
= render_if_exists "shared/boards/switcher", board: board
= form_tag page_filter_path, method: :get, class: 'filter-form js-filter-form w-100' do
@@ -13,7 +13,7 @@
- if @can_bulk_update
.check-all-holder.d-none.d-sm-block.hidden
= check_box_tag "check-all-issues", nil, false, class: "check-all-issues left"
- .issues-other-filters.filtered-search-wrapper
+ .issues-other-filters.filtered-search-wrapper.d-flex.flex-column.flex-md-row
.filtered-search-box
- if type != :boards_modal && type != :boards
= dropdown_tag(custom_icon('icon_history'),
@@ -147,7 +147,7 @@
%button.clear-search.hidden{ type: 'button' }
= icon('times')
- .filter-dropdown-container
+ .filter-dropdown-container.d-flex.flex-column.flex-md-row
- if type == :boards
.js-board-config{ data: { can_admin_list: user_can_admin_list, has_scope: board.scoped? } }
- if user_can_admin_list
diff --git a/app/workers/pages_domain_ssl_renewal_cron_worker.rb b/app/workers/pages_domain_ssl_renewal_cron_worker.rb
index 40c34d29970..e5dde07a648 100644
--- a/app/workers/pages_domain_ssl_renewal_cron_worker.rb
+++ b/app/workers/pages_domain_ssl_renewal_cron_worker.rb
@@ -5,9 +5,9 @@ class PagesDomainSslRenewalCronWorker
include CronjobQueue
def perform
- PagesDomain.need_auto_ssl_renewal.find_each do |domain|
- next unless ::Gitlab::LetsEncrypt.enabled?(domain)
+ return unless ::Gitlab::LetsEncrypt.enabled?
+ PagesDomain.need_auto_ssl_renewal.find_each do |domain|
PagesDomainSslRenewalWorker.perform_async(domain.id)
end
end
diff --git a/app/workers/pages_domain_ssl_renewal_worker.rb b/app/workers/pages_domain_ssl_renewal_worker.rb
index b32458ca777..87fd8059946 100644
--- a/app/workers/pages_domain_ssl_renewal_worker.rb
+++ b/app/workers/pages_domain_ssl_renewal_worker.rb
@@ -6,7 +6,7 @@ class PagesDomainSslRenewalWorker
def perform(domain_id)
domain = PagesDomain.find_by_id(domain_id)
return unless domain&.enabled?
- return unless ::Gitlab::LetsEncrypt.enabled?(domain)
+ return unless ::Gitlab::LetsEncrypt.enabled?
::PagesDomains::ObtainLetsEncryptCertificateService.new(domain).execute
end
diff --git a/bin/bundle b/bin/bundle
index 66e9889e8b4..f19acf5b5cc 100755
--- a/bin/bundle
+++ b/bin/bundle
@@ -1,3 +1,3 @@
#!/usr/bin/env ruby
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
load Gem.bin_path('bundler', 'bundle')
diff --git a/bin/setup b/bin/setup
index 883825bc0a2..94fd4d79775 100755
--- a/bin/setup
+++ b/bin/setup
@@ -1,33 +1,36 @@
#!/usr/bin/env ruby
-
-require "pathname"
+require 'fileutils'
+include FileUtils
# path to your application root.
-APP_ROOT = Pathname.new File.expand_path("../../", __FILE__)
+APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end
-Dir.chdir APP_ROOT do
- # This script is a starting point to set up your application.
- # Add necessary setup steps to this file:
+chdir APP_ROOT do
+ # This script is a starting point to setup your application.
+ # Add necessary setup steps to this file.
+
+ puts '== Installing dependencies =='
+ system! 'gem install bundler --conservative'
+ system('bundle check') || system!('bundle install')
- puts "== Installing dependencies =="
- system! "gem install bundler --conservative"
- system("bundle check") || system!("bundle install")
+ # Install JavaScript dependencies if using Yarn
+ # system('bin/yarn')
# puts "\n== Copying sample files =="
- # unless File.exist?("config/database.yml")
- # cp "config/database.yml.sample", "config/database.yml"
+ # unless File.exist?('config/database.yml')
+ # cp 'config/database.yml.sample', 'config/database.yml'
# end
puts "\n== Preparing database =="
- system! "bin/rails db:setup"
+ system! 'bin/rails db:setup'
puts "\n== Removing old logs and tempfiles =="
- system! "bin/rails log:clear tmp:clear"
+ system! 'bin/rails log:clear tmp:clear'
puts "\n== Restarting application server =="
- system! "bin/rails restart"
+ system! 'bin/rails restart'
end
diff --git a/bin/update b/bin/update
index a8e4462f203..58bfaed518c 100755
--- a/bin/update
+++ b/bin/update
@@ -1,10 +1,9 @@
#!/usr/bin/env ruby
-require 'pathname'
require 'fileutils'
include FileUtils
# path to your application root.
-APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
+APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
@@ -18,6 +17,9 @@ chdir APP_ROOT do
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
+ # Install JavaScript dependencies if using Yarn
+ # system('bin/yarn')
+
puts "\n== Updating database =="
system! 'bin/rails db:migrate'
diff --git a/bin/yarn b/bin/yarn
new file mode 100755
index 00000000000..460dd565b4a
--- /dev/null
+++ b/bin/yarn
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path('..', __dir__)
+Dir.chdir(APP_ROOT) do
+ begin
+ exec "yarnpkg", *ARGV
+ rescue Errno::ENOENT
+ $stderr.puts "Yarn executable was not detected in the system."
+ $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
+ exit 1
+ end
+end
diff --git a/changelogs/unreleased/51952-redirect-to-webide-in-fork.yml b/changelogs/unreleased/51952-redirect-to-webide-in-fork.yml
new file mode 100644
index 00000000000..ada0efca968
--- /dev/null
+++ b/changelogs/unreleased/51952-redirect-to-webide-in-fork.yml
@@ -0,0 +1,5 @@
+---
+title: Open WebIDE in fork when user doesn't have access
+merge_request: 30642
+author:
+type: changed
diff --git a/changelogs/unreleased/55623-group-cluster-apis.yml b/changelogs/unreleased/55623-group-cluster-apis.yml
new file mode 100644
index 00000000000..fe987ef4a82
--- /dev/null
+++ b/changelogs/unreleased/55623-group-cluster-apis.yml
@@ -0,0 +1,5 @@
+---
+title: Add API for CRUD group clusters
+merge_request: 30213
+author:
+type: added
diff --git a/changelogs/unreleased/57538-normalize-users-private-profile-field.yml b/changelogs/unreleased/57538-normalize-users-private-profile-field.yml
new file mode 100644
index 00000000000..85fc4cbf33c
--- /dev/null
+++ b/changelogs/unreleased/57538-normalize-users-private-profile-field.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate NULL values for users.private_profile column and update users API to reject null value for private_profile.
+merge_request: 29888
+author:
+type: changed
diff --git a/changelogs/unreleased/60666-kubernetes-applications-uninstall-runner.yml b/changelogs/unreleased/60666-kubernetes-applications-uninstall-runner.yml
new file mode 100644
index 00000000000..3632c8eec20
--- /dev/null
+++ b/changelogs/unreleased/60666-kubernetes-applications-uninstall-runner.yml
@@ -0,0 +1,5 @@
+---
+title: Allow GitLab Runner to be uninstalled from the UI
+merge_request: 30176
+author:
+type: added
diff --git a/changelogs/unreleased/61342-commit-search-result-doesn-t-pass-wcag-color-audit.yml b/changelogs/unreleased/61342-commit-search-result-doesn-t-pass-wcag-color-audit.yml
new file mode 100644
index 00000000000..f4ed4551aab
--- /dev/null
+++ b/changelogs/unreleased/61342-commit-search-result-doesn-t-pass-wcag-color-audit.yml
@@ -0,0 +1,5 @@
+---
+title: Change color for namespace in commit search
+merge_request: 30312
+author:
+type: other
diff --git a/changelogs/unreleased/61613-spacing-mr-widgets.yml b/changelogs/unreleased/61613-spacing-mr-widgets.yml
new file mode 100644
index 00000000000..7d37ef8da2e
--- /dev/null
+++ b/changelogs/unreleased/61613-spacing-mr-widgets.yml
@@ -0,0 +1,5 @@
+---
+title: Left align mr widget icons and text
+merge_request: 28561
+author:
+type: fixed
diff --git a/changelogs/unreleased/63298-prevent-excessive-sanitization-asciidoc.yml b/changelogs/unreleased/63298-prevent-excessive-sanitization-asciidoc.yml
new file mode 100644
index 00000000000..cd8206cdb99
--- /dev/null
+++ b/changelogs/unreleased/63298-prevent-excessive-sanitization-asciidoc.yml
@@ -0,0 +1,5 @@
+---
+title: "Prevent excessive sanitization of AsciiDoc ouptut"
+merge_request: 30290
+author: Guillaume Grossetie
+type: added \ No newline at end of file
diff --git a/changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml b/changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml
new file mode 100644
index 00000000000..51c1537a159
--- /dev/null
+++ b/changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml
@@ -0,0 +1,5 @@
+---
+title: "Enable section anchors in Asciidoctor"
+merge_request: 30666
+author: Guillaume Grossetie
+type: added \ No newline at end of file
diff --git a/changelogs/unreleased/64249-align-container-registry-empty-state-with-design-guidelines.yml b/changelogs/unreleased/64249-align-container-registry-empty-state-with-design-guidelines.yml
new file mode 100644
index 00000000000..ecdb4b6bed1
--- /dev/null
+++ b/changelogs/unreleased/64249-align-container-registry-empty-state-with-design-guidelines.yml
@@ -0,0 +1,5 @@
+---
+title: Alignign empty container registry message with design guidelines
+merge_request: 30502
+author:
+type: other
diff --git a/changelogs/unreleased/64407-vfazio-quirk-omniauth-strategies-openidconnect.yml b/changelogs/unreleased/64407-vfazio-quirk-omniauth-strategies-openidconnect.yml
new file mode 100644
index 00000000000..c2e300863fb
--- /dev/null
+++ b/changelogs/unreleased/64407-vfazio-quirk-omniauth-strategies-openidconnect.yml
@@ -0,0 +1,5 @@
+---
+title: Allow client authentication method to be configured for OpenID Connect
+merge_request: 30683
+author: Vincent Fazio
+type: fixed
diff --git a/changelogs/unreleased/64416-lodash-4-6-2-for-prototype-pollution.yml b/changelogs/unreleased/64416-lodash-4-6-2-for-prototype-pollution.yml
new file mode 100644
index 00000000000..cd8885233de
--- /dev/null
+++ b/changelogs/unreleased/64416-lodash-4-6-2-for-prototype-pollution.yml
@@ -0,0 +1,5 @@
+---
+title: Update lodash to 4.7.14 and lodash.mergewith to 4.6.2
+merge_request: 30602
+author: Takuya Noguchi
+type: security
diff --git a/changelogs/unreleased/bjk-fix_prom_example.yml b/changelogs/unreleased/bjk-fix_prom_example.yml
new file mode 100644
index 00000000000..2f81bc6196b
--- /dev/null
+++ b/changelogs/unreleased/bjk-fix_prom_example.yml
@@ -0,0 +1,5 @@
+---
+title: Update example Prometheus scrape config
+merge_request: 30739
+author:
+type: other
diff --git a/changelogs/unreleased/button-bug-fixes.yml b/changelogs/unreleased/button-bug-fixes.yml
new file mode 100644
index 00000000000..b63bfdf24ad
--- /dev/null
+++ b/changelogs/unreleased/button-bug-fixes.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Project Badge Button Styles
+merge_request: 30678
+author:
+type: fixed
diff --git a/changelogs/unreleased/bvl-rename-routes-after-user-rename.yml b/changelogs/unreleased/bvl-rename-routes-after-user-rename.yml
new file mode 100644
index 00000000000..8b0a01dea53
--- /dev/null
+++ b/changelogs/unreleased/bvl-rename-routes-after-user-rename.yml
@@ -0,0 +1,5 @@
+---
+title: Update a user's routes after updating their name
+merge_request: 23272
+author:
+type: fixed
diff --git a/changelogs/unreleased/fe-delete-old-boardservice-on-component-modal-footer.yml b/changelogs/unreleased/fe-delete-old-boardservice-on-component-modal-footer.yml
new file mode 100644
index 00000000000..4392b72443b
--- /dev/null
+++ b/changelogs/unreleased/fe-delete-old-boardservice-on-component-modal-footer.yml
@@ -0,0 +1,6 @@
+---
+title: change the use of boardService in favor of boardsStore on footer for the board
+ component
+merge_request: 30616
+author: eduarmreyes
+type: other
diff --git a/changelogs/unreleased/fix-broken-vue-i18n-strings.yml b/changelogs/unreleased/fix-broken-vue-i18n-strings.yml
new file mode 100644
index 00000000000..69cec8a6b1b
--- /dev/null
+++ b/changelogs/unreleased/fix-broken-vue-i18n-strings.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken warnings while Editing Issues and Edit File on MR
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-comment-race-condition.yml b/changelogs/unreleased/fix-comment-race-condition.yml
new file mode 100644
index 00000000000..d1f5b8fe01f
--- /dev/null
+++ b/changelogs/unreleased/fix-comment-race-condition.yml
@@ -0,0 +1,5 @@
+---
+title: Fix commenting before discussions are loaded
+merge_request: 30724
+author:
+type: fixed
diff --git a/changelogs/unreleased/georgekoltsov-63955-fix-import-with-source-branch-deleted.yml b/changelogs/unreleased/georgekoltsov-63955-fix-import-with-source-branch-deleted.yml
new file mode 100644
index 00000000000..72e2621c52a
--- /dev/null
+++ b/changelogs/unreleased/georgekoltsov-63955-fix-import-with-source-branch-deleted.yml
@@ -0,0 +1,5 @@
+---
+title: Fix a bug that prevented projects containing merge request diff comments from being imported
+merge_request: 30630
+author:
+type: fixed
diff --git a/changelogs/unreleased/hide-restricted-visibility-radio.yml b/changelogs/unreleased/hide-restricted-visibility-radio.yml
new file mode 100644
index 00000000000..ebc8b787890
--- /dev/null
+++ b/changelogs/unreleased/hide-restricted-visibility-radio.yml
@@ -0,0 +1,5 @@
+---
+title: Hide restricted and disallowed visibility radios
+merge_request: 30590
+author:
+type: fixed
diff --git a/changelogs/unreleased/id-clean-up-mr-assignees.yml b/changelogs/unreleased/id-clean-up-mr-assignees.yml
new file mode 100644
index 00000000000..7ff03c9f00b
--- /dev/null
+++ b/changelogs/unreleased/id-clean-up-mr-assignees.yml
@@ -0,0 +1,5 @@
+---
+title: Add cleanup migration for MR's multiple assignees
+merge_request: 30261
+author:
+type: changed
diff --git a/changelogs/unreleased/jc-remove-catfile-flag.yml b/changelogs/unreleased/jc-remove-catfile-flag.yml
new file mode 100644
index 00000000000..6b72de7bc45
--- /dev/null
+++ b/changelogs/unreleased/jc-remove-catfile-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove catfile cache feature flag
+merge_request: 30750
+author:
+type: performance
diff --git a/changelogs/unreleased/mh-boards-filter-bar.yml b/changelogs/unreleased/mh-boards-filter-bar.yml
new file mode 100644
index 00000000000..3e91b5ef443
--- /dev/null
+++ b/changelogs/unreleased/mh-boards-filter-bar.yml
@@ -0,0 +1,5 @@
+---
+title: Display boards filter bar on mobile
+merge_request: 30120
+author:
+type: fixed
diff --git a/changelogs/unreleased/mh-mermaid-linebreaks.yml b/changelogs/unreleased/mh-mermaid-linebreaks.yml
new file mode 100644
index 00000000000..e38820d8ce3
--- /dev/null
+++ b/changelogs/unreleased/mh-mermaid-linebreaks.yml
@@ -0,0 +1,5 @@
+---
+title: Fix linebreak rendering in Mermaid flowcharts
+merge_request: 30730
+author:
+type: fixed
diff --git a/changelogs/unreleased/remove-auto-ssl-ff.yml b/changelogs/unreleased/remove-auto-ssl-ff.yml
new file mode 100644
index 00000000000..1b4d0dcde08
--- /dev/null
+++ b/changelogs/unreleased/remove-auto-ssl-ff.yml
@@ -0,0 +1,6 @@
+---
+title: Add support for generating SSL certificates for custon pages domains through
+ Let's Encrypt
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/remove-support-for-legacy-pipeline-triggers.yml b/changelogs/unreleased/remove-support-for-legacy-pipeline-triggers.yml
new file mode 100644
index 00000000000..3f4d4bbd432
--- /dev/null
+++ b/changelogs/unreleased/remove-support-for-legacy-pipeline-triggers.yml
@@ -0,0 +1,5 @@
+---
+title: Remove support for legacy pipeline triggers
+merge_request: 30133
+author:
+type: removed
diff --git a/changelogs/unreleased/sh-audit-event-json-log-format-from-and-to.yml b/changelogs/unreleased/sh-audit-event-json-log-format-from-and-to.yml
new file mode 100644
index 00000000000..5bd21d7ef2b
--- /dev/null
+++ b/changelogs/unreleased/sh-audit-event-json-log-format-from-and-to.yml
@@ -0,0 +1,5 @@
+---
+title: Format `from` and `to` fields in JSON audit log
+merge_request: 30333
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-fix-httpclient-ssl.yml b/changelogs/unreleased/sh-fix-httpclient-ssl.yml
new file mode 100644
index 00000000000..fda4e2e7084
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-httpclient-ssl.yml
@@ -0,0 +1,5 @@
+---
+title: Make httpclient respect system SSL configuration
+merge_request: 30749
+author:
+type: fixed
diff --git a/changelogs/unreleased/update-pages-to-1-7-0.yml b/changelogs/unreleased/update-pages-to-1-7-0.yml
new file mode 100644
index 00000000000..d41346f021c
--- /dev/null
+++ b/changelogs/unreleased/update-pages-to-1-7-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Pages to v1.7.0
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/z-index-fix-for-diff-file-dropdown.yml b/changelogs/unreleased/z-index-fix-for-diff-file-dropdown.yml
new file mode 100644
index 00000000000..72108f6ab77
--- /dev/null
+++ b/changelogs/unreleased/z-index-fix-for-diff-file-dropdown.yml
@@ -0,0 +1,5 @@
+---
+title: I fixed z index bug in diff page
+merge_request: 30657
+author: Faruk Can
+type: fixed
diff --git a/config/application.rb b/config/application.rb
index edf8b3e87f9..de386506233 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -1,8 +1,14 @@
-require File.expand_path('boot', __dir__)
+require_relative 'boot'
-require 'rails/all'
+# Based on https://github.com/rails/rails/blob/v5.2.3/railties/lib/rails/all.rb
+# Only load the railties we need instead of loading everything
+require 'active_record/railtie'
+require 'action_controller/railtie'
+require 'action_view/railtie'
+require 'action_mailer/railtie'
+require 'rails/test_unit/railtie'
-Bundler.require(:default, Rails.env)
+Bundler.require(*Rails.groups)
module Gitlab
class Application < Rails::Application
@@ -25,6 +31,8 @@ module Gitlab
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
+ config.active_record.sqlite3.represent_boolean_as_integer = true
+
# Sidekiq uses eager loading, but directories not in the standard Rails
# directories must be added to the eager load paths:
# https://github.com/mperham/sidekiq/wiki/FAQ#why-doesnt-sidekiq-autoload-my-rails-application-code
@@ -86,13 +94,6 @@ module Gitlab
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
- # ActionCable mount point.
- # The default Rails' mount point is `/cable` which may conflict with existing
- # namespaces/users.
- # https://github.com/rails/rails/blob/5-0-stable/actioncable/lib/action_cable.rb#L38
- # Please change this value when configuring ActionCable for real usage.
- config.action_cable.mount_path = "/-/cable"
-
# Configure sensitive parameters which will be filtered from the log file.
#
# Parameters filtered:
@@ -272,5 +273,10 @@ module Gitlab
Gitlab::Routing.add_helpers(project_url_helpers)
Gitlab::Routing.add_helpers(MilestonesRoutingHelper)
end
+
+ # This makes generated cookies to be compatible with Rails 5.1 and older
+ # We can remove this when we're confident that there are no issues with the Rails 5.2 upgrade
+ # and we won't need to rollback to older versions
+ config.action_dispatch.use_authenticated_cookie_encryption = false
end
end
diff --git a/config/environments/development.rb b/config/environments/development.rb
index ac9b02b08d5..3881f1be152 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -7,6 +7,7 @@ Rails.application.configure do
config.cache_classes = false
# Show full error reports and disable caching
+ config.active_record.verbose_query_logs = true
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
diff --git a/config/environments/test.rb b/config/environments/test.rb
index e7166882eea..153d16e4e55 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -23,6 +23,7 @@ Rails.application.configure do
config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
# Show full error reports and disable caching
+ config.active_record.verbose_query_logs = true
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
@@ -40,7 +41,7 @@ Rails.application.configure do
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
- config.eager_load = false
+ config.eager_load = true
config.cache_store = :null_store
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 334c241bcaa..0e78980350f 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -952,6 +952,16 @@ production: &base
# address: localhost
# port: 3807
+ ## Prometheus settings
+ # Do not modify these settings here. They should be modified in /etc/gitlab/gitlab.rb
+ # if you installed GitLab via Omnibus.
+ # If you installed from source, you need to install and configure Prometheus
+ # yourself, and then update the values here.
+ # https://docs.gitlab.com/ee/administration/monitoring/prometheus/
+ prometheus:
+ # enable: true
+ # listen_address: 'localhost:9090'
+
#
# 5. Extra customization
# ==========================
@@ -1158,6 +1168,9 @@ test:
user_filter: ''
group_base: 'ou=groups,dc=example,dc=com'
admin_group: ''
+ prometheus:
+ enable: true
+ listen_address: 'localhost:9090'
staging:
<<: *base
diff --git a/config/initializers/active_record_data_types.rb b/config/initializers/active_record_data_types.rb
index e95157bfde5..151bce4d130 100644
--- a/config/initializers/active_record_data_types.rb
+++ b/config/initializers/active_record_data_types.rb
@@ -22,7 +22,7 @@ if Gitlab::Database.postgresql?
#
# When schema dumping, `timestamptz` columns will be output as
# `t.datetime_with_timezone`.
- def initialize_type_map(mapping)
+ def initialize_type_map(mapping = type_map)
super mapping
mapping.register_type 'timestamptz' do |_, _, sql_type|
@@ -51,7 +51,7 @@ elsif Gitlab::Database.mysql?
#
# When schema dumping, `timestamp` columns will be output as
# `t.datetime_with_timezone`.
- def initialize_type_map(mapping)
+ def initialize_type_map(mapping = type_map)
super mapping
mapping.register_type(/timestamp/i) do |sql_type|
diff --git a/config/initializers/active_record_preloader.rb b/config/initializers/active_record_preloader.rb
index 3b16014f302..a293909149e 100644
--- a/config/initializers/active_record_preloader.rb
+++ b/config/initializers/active_record_preloader.rb
@@ -1,9 +1,22 @@
module ActiveRecord
module Associations
class Preloader
+ class NullPreloader
+ def self.new(klass, owners, reflection, preload_scope)
+ self
+ end
+
+ def self.run(preloader)
+ end
+
+ def self.preloaded_records
+ []
+ end
+ end
+
module NoCommitPreloader
- def preloader_for(reflection, owners, rhs_klass)
- return NullPreloader if rhs_klass == ::Commit
+ def preloader_for(reflection, owners)
+ return NullPreloader if owners.first.association(reflection.name).klass == ::Commit
super
end
diff --git a/config/initializers/active_record_query_cache.rb b/config/initializers/active_record_query_cache.rb
new file mode 100644
index 00000000000..61505a1edd3
--- /dev/null
+++ b/config/initializers/active_record_query_cache.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+ActiveRecord::ConnectionAdapters::ConnectionPool.prepend Gitlab::Patch::ActiveRecordQueryCache
diff --git a/config/initializers/active_record_verbose_query_logs.rb b/config/initializers/active_record_verbose_query_logs.rb
deleted file mode 100644
index 1c5fbc8e830..00000000000
--- a/config/initializers/active_record_verbose_query_logs.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-# This is backport of https://github.com/rails/rails/pull/26815/files
-# Enabled by default for every non-production environment
-
-module ActiveRecord
- class LogSubscriber
- module VerboseQueryLogs
- def debug(progname = nil, &block)
- return unless super
-
- log_query_source
- end
-
- def log_query_source
- source_line, line_number = extract_callstack(caller_locations)
-
- if source_line
- if defined?(::Rails.root)
- app_root = "#{::Rails.root}/".freeze
- source_line = source_line.sub(app_root, "")
- end
-
- logger.debug(" ↳ #{source_line}:#{line_number}")
- end
- end
-
- def extract_callstack(callstack)
- line = callstack.find do |frame|
- frame.absolute_path && !ignored_callstack(frame.absolute_path)
- end
-
- offending_line = line || callstack.first
- [
- offending_line.path,
- offending_line.lineno,
- offending_line.label
- ]
- end
-
- LOG_SUBSCRIBER_FILE = ActiveRecord::LogSubscriber.method(:logger).source_location.first
- RAILS_GEM_ROOT = File.expand_path("../../../..", LOG_SUBSCRIBER_FILE) + "/"
- APP_CONFIG_ROOT = File.expand_path("..", __dir__) + "/"
-
- def ignored_callstack(path)
- path.start_with?(APP_CONFIG_ROOT, RAILS_GEM_ROOT, RbConfig::CONFIG["rubylibdir"])
- end
- end
-
- if Rails.version.start_with?("5.2")
- raise "Remove this monkey patch: #{__FILE__}"
- else
- prepend(VerboseQueryLogs) unless Rails.env.production?
- end
- end
-end
diff --git a/config/initializers/ar_speed_up_migration_checking.rb b/config/initializers/ar_speed_up_migration_checking.rb
index f98b246db0b..c4ffcc54cb2 100644
--- a/config/initializers/ar_speed_up_migration_checking.rb
+++ b/config/initializers/ar_speed_up_migration_checking.rb
@@ -2,17 +2,14 @@ if Rails.env.test?
require 'active_record/migration'
module ActiveRecord
- class Migrator
- class << self
- alias_method :migrations_unmemoized, :migrations
+ class MigrationContext
+ alias_method :migrations_unmemoized, :migrations
- # This method is called a large number of times per rspec example, and
- # it reads + parses `db/migrate/*` each time. Memoizing it can save 0.5
- # seconds per spec.
- def migrations(paths)
- @migrations ||= {}
- (@migrations[paths] ||= migrations_unmemoized(paths)).dup
- end
+ # This method is called a large number of times per rspec example, and
+ # it reads + parses `db/migrate/*` each time. Memoizing it can save 0.5
+ # seconds per spec.
+ def migrations
+ @migrations ||= migrations_unmemoized
end
end
end
diff --git a/config/initializers/config_initializers_active_record_locking.rb b/config/initializers/config_initializers_active_record_locking.rb
index 608d63223a3..915247826e9 100644
--- a/config/initializers/config_initializers_active_record_locking.rb
+++ b/config/initializers/config_initializers_active_record_locking.rb
@@ -22,10 +22,11 @@ module ActiveRecord
# Patched because when `lock_version` is read as `0`, it may actually be `NULL` in the DB.
possible_previous_lock_value = previous_lock_value.to_i == 0 ? [nil, 0] : previous_lock_value
- affected_rows = self.class.unscoped._update_record(
- arel_attributes_with_values(attribute_names),
- self.class.primary_key => id_in_database,
- locking_column => possible_previous_lock_value
+ affected_rows = self.class.unscoped.where(
+ locking_column => possible_previous_lock_value,
+ self.class.primary_key => id_in_database
+ ).update_all(
+ attributes_with_values_for_update(attribute_names)
)
if affected_rows != 1
diff --git a/config/initializers/httpclient_patch.rb b/config/initializers/httpclient_patch.rb
new file mode 100644
index 00000000000..22cc5605d9b
--- /dev/null
+++ b/config/initializers/httpclient_patch.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# By default, httpclient (and hence anything that uses rack-oauth2)
+# ignores the system-wide SSL certificate configuration in favor of its
+# own cacert.pem. This makes it impossible to use custom certificates
+# without patching that file. Until
+# https://github.com/nahi/httpclient/pull/386 is merged, we work around
+# this limitation by forcing the HTTPClient SSL store to use the default
+# system configuration.
+module HTTPClient::SSLConfigDefaultPaths
+ def initialize(client)
+ super
+
+ set_default_paths
+ end
+end
+
+HTTPClient::SSLConfig.prepend HTTPClient::SSLConfigDefaultPaths
diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb
index 1ad93e14f7e..fbec28186eb 100644
--- a/config/initializers/lograge.rb
+++ b/config/initializers/lograge.rb
@@ -18,7 +18,7 @@ unless Sidekiq.server?
.map { |k, v| { key: k, value: v } }
payload = {
- time: event.time.utc.iso8601(3),
+ time: Time.now.utc.iso8601(3),
params: params,
remote_ip: event.payload[:remote_ip],
user_id: event.payload[:user_id],
diff --git a/config/initializers/mysql_ignore_postgresql_options.rb b/config/initializers/mysql_ignore_postgresql_options.rb
index 9a569be7674..e6a7d9bef52 100644
--- a/config/initializers/mysql_ignore_postgresql_options.rb
+++ b/config/initializers/mysql_ignore_postgresql_options.rb
@@ -15,7 +15,6 @@ if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
module ConnectionAdapters
class Mysql2Adapter < AbstractMysqlAdapter
alias_method :__gitlab_add_index, :add_index
- alias_method :__gitlab_add_index_sql, :add_index_sql
alias_method :__gitlab_add_index_options, :add_index_options
def add_index(table_name, column_name, options = {})
@@ -24,12 +23,6 @@ if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
end
end
- def add_index_sql(table_name, column_name, options = {})
- unless options[:opclasses]
- __gitlab_add_index_sql(table_name, column_name, options)
- end
- end
-
def add_index_options(table_name, column_name, options = {})
if options[:using] && options[:using] == :gin
options = options.dup
diff --git a/config/initializers/postgresql_cte.rb b/config/initializers/postgresql_cte.rb
index 56689bc8e74..68d53c4edbf 100644
--- a/config/initializers/postgresql_cte.rb
+++ b/config/initializers/postgresql_cte.rb
@@ -94,8 +94,8 @@ module ActiveRecord
end
end
- def build_arel
- arel = super()
+ def build_arel(aliases)
+ arel = super
build_with(arel) if @values[:with]
diff --git a/config/initializers/zz_metrics.rb b/config/initializers/zz_metrics.rb
index 5aa6f73c5c5..4f309094447 100644
--- a/config/initializers/zz_metrics.rb
+++ b/config/initializers/zz_metrics.rb
@@ -53,7 +53,7 @@ def instrument_classes(instrumentation)
instrumentation.instrument_methods(Banzai::Querying)
instrumentation.instrument_instance_methods(Banzai::ObjectRenderer)
- instrumentation.instrument_instance_methods(Banzai::Redactor)
+ instrumentation.instrument_instance_methods(Banzai::ReferenceRedactor)
[Issuable, Mentionable, Participable].each do |klass|
instrumentation.instrument_instance_methods(klass)
diff --git a/config/routes.rb b/config/routes.rb
index 50bb092ec2e..641807203bf 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -110,6 +110,12 @@ Rails.application.routes.draw do
draw :jira_connect
end
+ Gitlab.ee do
+ constraints(::Constraints::FeatureConstrainer.new(:analytics)) do
+ draw :analytics
+ end
+ end
+
if ENV['GITLAB_CHAOS_SECRET'] || Rails.env.development?
resource :chaos, only: [] do
get :leakmem
diff --git a/config/webpack.config.js b/config/webpack.config.js
index a81590e8b8e..cd793743eb7 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -344,6 +344,8 @@ module.exports = {
devtool: NO_SOURCEMAPS ? false : devtool,
- // sqljs requires fs
- node: { fs: 'empty' },
+ node: {
+ fs: 'empty', // sqljs requires fs
+ setImmediate: false,
+ },
};
diff --git a/danger/commit_messages/Dangerfile b/danger/commit_messages/Dangerfile
index ec494635f02..0c675cc4c9c 100644
--- a/danger/commit_messages/Dangerfile
+++ b/danger/commit_messages/Dangerfile
@@ -88,6 +88,19 @@ def lint_commit(commit) # rubocop:disable Metrics/AbcSize
# We ignore revert commits as they are well structured by Git already
return false if commit.message.start_with?('Revert "')
+ # Fail if a suggestion commit is used and squash is not enabled
+ if commit.message.start_with?('Apply suggestion to')
+ if gitlab.mr_json['squash']
+ return false
+ else
+ fail_commit(
+ commit,
+ 'If you are applying suggestions, enable squash in the merge request and re-run the failed job'
+ )
+ return true
+ end
+ end
+
failures = false
subject, separator, details = commit.message.split("\n", 3)
@@ -114,16 +127,6 @@ def lint_commit(commit) # rubocop:disable Metrics/AbcSize
)
end
- # Fail if a suggestion commit is used and squash is not enabled
- if commit.message.start_with?('Apply suggestion to') && !gitlab.mr_json['squash']
- fail_commit(
- commit,
- 'If you are applying suggestions, squash needs to be enabled in the merge request'
- )
-
- failures = true
- end
-
unless subject_starts_with_capital?(subject)
fail_commit(commit, 'The commit subject must start with a capital letter')
failures = true
diff --git a/db/migrate/20190620105427_change_null_private_profile_to_false.rb b/db/migrate/20190620105427_change_null_private_profile_to_false.rb
new file mode 100644
index 00000000000..d820dbbe9d3
--- /dev/null
+++ b/db/migrate/20190620105427_change_null_private_profile_to_false.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class ChangeNullPrivateProfileToFalse < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ DELAY = 30.seconds.to_i
+ BATCH_SIZE = 1_000
+
+ disable_ddl_transaction!
+
+ class User < ActiveRecord::Base
+ self.table_name = 'users'
+
+ include ::EachBatch
+ end
+
+ def up
+ change_column_default :users, :private_profile, false
+
+ # Migration will take about 120 hours
+ User.where(private_profile: nil).each_batch(of: BATCH_SIZE) do |batch, index|
+ range = batch.pluck('MIN(id)', 'MAX(id)').first
+ delay = index * DELAY
+
+ BackgroundMigrationWorker.perform_in(delay.seconds, 'MigrateNullPrivateProfileToFalse', [*range])
+ end
+ end
+
+ def down
+ change_column_default :users, :private_profile, nil
+ end
+end
diff --git a/db/post_migrate/20190628191740_schedule_fixing_names_of_user_namespaces.rb b/db/post_migrate/20190628191740_schedule_fixing_names_of_user_namespaces.rb
new file mode 100644
index 00000000000..8fa7068b957
--- /dev/null
+++ b/db/post_migrate/20190628191740_schedule_fixing_names_of_user_namespaces.rb
@@ -0,0 +1,48 @@
+# 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 ScheduleFixingNamesOfUserNamespaces < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ class Namespace < ActiveRecord::Base
+ include ::EachBatch
+
+ self.table_name = 'namespaces'
+
+ scope :user_namespaces, -> { where(type: nil) }
+ end
+
+ class Route < ActiveRecord::Base
+ include ::EachBatch
+
+ self.table_name = 'routes'
+
+ scope :project_routes, -> { where(source_type: 'Project') }
+ end
+
+ disable_ddl_transaction!
+
+ def up
+ queue_background_migration_jobs_by_range_at_intervals(
+ ScheduleFixingNamesOfUserNamespaces::Namespace.user_namespaces,
+ 'FixUserNamespaceNames',
+ 60.seconds,
+ batch_size: 5000
+ )
+
+ queue_background_migration_jobs_by_range_at_intervals(
+ ScheduleFixingNamesOfUserNamespaces::Route.project_routes,
+ 'FixUserProjectRouteNames',
+ 60.seconds,
+ batch_size: 5000
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20190702173936_populate_remaining_merge_request_assignees.rb b/db/post_migrate/20190702173936_populate_remaining_merge_request_assignees.rb
new file mode 100644
index 00000000000..c435b94015d
--- /dev/null
+++ b/db/post_migrate/20190702173936_populate_remaining_merge_request_assignees.rb
@@ -0,0 +1,20 @@
+# 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 PopulateRemainingMergeRequestAssignees < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ BATCH_SIZE = 10_000
+ MIGRATION = 'PopulateMergeRequestAssigneesTable'
+
+ disable_ddl_transaction!
+
+ def up
+ Gitlab::BackgroundMigration.steal(MIGRATION)
+
+ Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable.new.perform_all_sync(batch_size: BATCH_SIZE)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 9a8b64689bd..644ca1fe970 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,11 +10,11 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20190703130053) do
+ActiveRecord::Schema.define(version: 2019_07_03_130053) do
# These are extensions that must be enabled in order to support this database
- enable_extension "plpgsql"
enable_extension "pg_trgm"
+ enable_extension "plpgsql"
create_table "abuse_reports", id: :serial, force: :cascade do |t|
t.integer "reporter_id"
@@ -63,6 +63,7 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.datetime "updated_at"
t.string "home_page_url"
t.integer "default_branch_protection", default: 2
+ t.text "help_text"
t.text "restricted_visibility_levels"
t.boolean "version_check_enabled", default: true
t.integer "max_attachment_size", default: 10, null: false
@@ -104,6 +105,8 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.integer "container_registry_token_expire_delay", default: 5
t.text "after_sign_up_text"
t.boolean "user_default_external", default: false, null: false
+ t.boolean "elasticsearch_indexing", default: false, null: false
+ t.boolean "elasticsearch_search", default: false, null: false
t.string "repository_storages", default: "default"
t.string "enabled_git_access_protocol"
t.boolean "domain_blacklist_enabled", default: false
@@ -125,18 +128,37 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.boolean "html_emails_enabled", default: true
t.string "plantuml_url"
t.boolean "plantuml_enabled"
+ t.integer "shared_runners_minutes", default: 0, null: false
+ t.bigint "repository_size_limit", default: 0
t.integer "terminal_max_session_time", default: 0, null: false
t.integer "unique_ips_limit_per_user"
t.integer "unique_ips_limit_time_window"
t.boolean "unique_ips_limit_enabled", default: false, null: false
t.string "default_artifacts_expire_in", default: "0", null: false
+ t.string "elasticsearch_url", default: "http://localhost:9200"
+ t.boolean "elasticsearch_aws", default: false, null: false
+ t.string "elasticsearch_aws_region", default: "us-east-1"
+ t.string "elasticsearch_aws_access_key"
+ t.string "elasticsearch_aws_secret_access_key"
+ t.integer "geo_status_timeout", default: 10
t.string "uuid"
t.decimal "polling_interval_multiplier", default: "1.0", null: false
+ t.boolean "elasticsearch_experimental_indexer"
t.integer "cached_markdown_version"
+ t.boolean "check_namespace_plan", default: false, null: false
+ t.integer "mirror_max_delay", default: 300, null: false
+ t.integer "mirror_max_capacity", default: 100, null: false
+ t.integer "mirror_capacity_threshold", default: 50, null: false
t.boolean "prometheus_metrics_enabled", default: true, null: false
+ t.boolean "authorized_keys_enabled", default: true, null: false
t.boolean "help_page_hide_commercial_content", default: false
t.string "help_page_support_url"
+ t.boolean "slack_app_enabled", default: false
+ t.string "slack_app_id"
+ t.string "slack_app_secret"
+ t.string "slack_app_verification_token"
t.integer "performance_bar_allowed_group_id"
+ t.boolean "allow_group_owners_to_manage_ldap", default: true, null: false
t.boolean "hashed_storage_enabled", default: true, null: false
t.boolean "project_export_enabled", default: true, null: false
t.boolean "auto_devops_enabled", default: true, null: false
@@ -149,22 +171,38 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.boolean "throttle_authenticated_web_enabled", default: false, null: false
t.integer "throttle_authenticated_web_requests_per_period", default: 7200, null: false
t.integer "throttle_authenticated_web_period_in_seconds", default: 3600, null: false
- t.boolean "password_authentication_enabled_for_web"
- t.boolean "password_authentication_enabled_for_git", default: true, null: false
t.integer "gitaly_timeout_default", default: 55, null: false
t.integer "gitaly_timeout_medium", default: 30, null: false
t.integer "gitaly_timeout_fast", default: 10, null: false
- t.boolean "authorized_keys_enabled", default: true, null: false
+ t.boolean "mirror_available", default: true, null: false
+ t.boolean "password_authentication_enabled_for_web"
+ t.boolean "password_authentication_enabled_for_git", default: true, null: false
t.string "auto_devops_domain"
+ t.boolean "external_authorization_service_enabled", default: false, null: false
+ t.string "external_authorization_service_url"
+ t.string "external_authorization_service_default_label"
t.boolean "pages_domain_verification_enabled", default: true, null: false
t.string "user_default_internal_regex"
t.boolean "allow_local_requests_from_hooks_and_services", default: false, null: false
+ t.float "external_authorization_service_timeout", default: 0.5
+ t.text "external_auth_client_cert"
+ t.text "encrypted_external_auth_client_key"
+ t.string "encrypted_external_auth_client_key_iv"
+ t.string "encrypted_external_auth_client_key_pass"
+ t.string "encrypted_external_auth_client_key_pass_iv"
+ t.string "email_additional_text"
t.boolean "enforce_terms", default: false
- t.boolean "mirror_available", default: true, null: false
+ t.integer "file_template_project_id"
+ t.boolean "pseudonymizer_enabled", default: false, null: false
t.boolean "hide_third_party_offers", default: false, null: false
+ t.boolean "snowplow_enabled", default: false, null: false
+ t.string "snowplow_collector_uri"
+ t.string "snowplow_site_id"
+ t.string "snowplow_cookie_domain"
t.boolean "instance_statistics_visibility_private", default: false, null: false
t.boolean "web_ide_clientside_preview_enabled", default: false, null: false
t.boolean "user_show_add_ssh_key_message", default: true, null: false
+ t.integer "custom_project_templates_group_id"
t.integer "usage_stats_set_by_user_id"
t.integer "receive_max_input_size"
t.integer "diff_max_patch_bytes", default: 102400, null: false
@@ -174,18 +212,11 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.string "runners_registration_token_encrypted"
t.integer "local_markdown_version", default: 0, null: false
t.integer "first_day_of_week", default: 0, null: false
+ t.boolean "elasticsearch_limit_indexing", default: false, null: false
t.integer "default_project_creation", default: 2, null: false
- t.boolean "external_authorization_service_enabled", default: false, null: false
- t.string "external_authorization_service_url"
- t.string "external_authorization_service_default_label"
- t.float "external_authorization_service_timeout", default: 0.5
- t.text "external_auth_client_cert"
- t.text "encrypted_external_auth_client_key"
- t.string "encrypted_external_auth_client_key_iv"
- t.string "encrypted_external_auth_client_key_pass"
- t.string "encrypted_external_auth_client_key_pass_iv"
t.string "lets_encrypt_notification_email"
t.boolean "lets_encrypt_terms_of_service_accepted", default: false, null: false
+ t.string "geo_node_allowed_ips", default: "0.0.0.0/0, ::/0"
t.integer "elasticsearch_shards", default: 5, null: false
t.integer "elasticsearch_replicas", default: 1, null: false
t.text "encrypted_lets_encrypt_private_key"
@@ -195,37 +226,6 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.boolean "default_project_deletion_protection", default: false, null: false
t.boolean "grafana_enabled", default: false, null: false
t.boolean "lock_memberships_to_ldap", default: false, null: false
- t.text "help_text"
- t.boolean "elasticsearch_indexing", default: false, null: false
- t.boolean "elasticsearch_search", default: false, null: false
- t.integer "shared_runners_minutes", default: 0, null: false
- t.bigint "repository_size_limit", default: 0
- t.string "elasticsearch_url", default: "http://localhost:9200"
- t.boolean "elasticsearch_aws", default: false, null: false
- t.string "elasticsearch_aws_region", default: "us-east-1"
- t.string "elasticsearch_aws_access_key"
- t.string "elasticsearch_aws_secret_access_key"
- t.integer "geo_status_timeout", default: 10
- t.boolean "elasticsearch_experimental_indexer"
- t.boolean "check_namespace_plan", default: false, null: false
- t.integer "mirror_max_delay", default: 300, null: false
- t.integer "mirror_max_capacity", default: 100, null: false
- t.integer "mirror_capacity_threshold", default: 50, null: false
- t.boolean "slack_app_enabled", default: false
- t.string "slack_app_id"
- t.string "slack_app_secret"
- t.string "slack_app_verification_token"
- t.boolean "allow_group_owners_to_manage_ldap", default: true, null: false
- t.string "email_additional_text"
- t.integer "file_template_project_id"
- t.boolean "pseudonymizer_enabled", default: false, null: false
- t.boolean "snowplow_enabled", default: false, null: false
- t.string "snowplow_collector_uri"
- t.string "snowplow_site_id"
- t.string "snowplow_cookie_domain"
- t.integer "custom_project_templates_group_id"
- t.boolean "elasticsearch_limit_indexing", default: false, null: false
- t.string "geo_node_allowed_ips", default: "0.0.0.0/0, ::/0"
t.boolean "time_tracking_limit_to_hours", default: false, null: false
t.string "grafana_url", default: "/-/grafana", null: false
t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id", using: :btree
@@ -405,10 +405,10 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.integer "project_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.integer "group_id"
+ t.string "name", default: "Development", null: false
t.integer "milestone_id"
+ t.integer "group_id"
t.integer "weight"
- t.string "name", default: "Development", null: false
t.index ["group_id"], name: "index_boards_on_group_id", using: :btree
t.index ["milestone_id"], name: "index_boards_on_milestone_id", using: :btree
t.index ["project_id"], name: "index_boards_on_project_id", using: :btree
@@ -3391,7 +3391,7 @@ ActiveRecord::Schema.define(version: 20190703130053) do
t.integer "theme_id", limit: 2
t.integer "accepted_term_id"
t.string "feed_token"
- t.boolean "private_profile"
+ t.boolean "private_profile", default: false
t.boolean "include_private_contributions"
t.string "commit_email"
t.boolean "auditor", default: false, null: false
diff --git a/doc/README.md b/doc/README.md
index 25db0efb960..bf7017d8fb4 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -108,7 +108,7 @@ The following documentation relates to the DevOps **Plan** stage:
| Plan Topics | Description |
|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------|
| [Burndown Charts](user/project/milestones/burndown_charts.md) **(STARTER)** | Watch your project's progress throughout a specific milestone. |
-| [Discussions](user/discussions/index.md) | Threads, comments, and resolvable discussions in issues, commits, and merge requests. |
+| [Discussions](user/discussions/index.md) | Threads, comments, and resolvable threads in issues, commits, and merge requests. |
| [Due Dates](user/project/issues/due_dates.md) | Keep track of issue deadlines. |
| [Epics](user/group/epics/index.md) **(ULTIMATE)** | Tracking groups of issues that share a theme. |
| [Issues](user/project/issues/index.md), including [confidential issues](user/project/issues/confidential_issues.md),<br/>[issue and merge request templates](user/project/description_templates.md),<br/>and [moving issues](user/project/issues/managing_issues.md#moving-issues) | Project issues, restricting access to issues, create templates for submitting new issues and merge requests, and moving issues between projects. |
@@ -192,7 +192,7 @@ The following documentation relates to the DevOps **Create** stage:
|:------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------|
| [Checking out merge requests locally](user/project/merge_requests/index.md#checkout-merge-requests-locally) | Tips for working with merge requests locally. |
| [Cherry-picking](user/project/merge_requests/cherry_pick_changes.md) | Use GitLab for cherry-picking changes. |
-| [Merge request discussion resolution](user/discussions/index.md#moving-a-single-discussion-to-a-new-issue) | Resolve discussions, move discussions in a merge request to an issue, and only allow merge requests to be merged if all discussions are resolved. |
+| [Merge request thread resolution](user/discussions/index.md#moving-a-single-thread-to-a-new-issue) | Resolve threads, move threads in a merge request to an issue, and only allow merge requests to be merged if all threads are resolved. |
| [Merge requests](user/project/merge_requests/index.md) | Merge request management. |
| [Work In Progress "WIP" merge requests](user/project/merge_requests/work_in_progress_merge_requests.md) | Prevent merges of work-in-progress merge requests. |
diff --git a/doc/administration/auth/README.md b/doc/administration/auth/README.md
index d8094587d14..2fc9db0632e 100644
--- a/doc/administration/auth/README.md
+++ b/doc/administration/auth/README.md
@@ -1,19 +1,34 @@
---
comments: false
+type: index
---
-# Authentication and Authorization
+# GitLab authentication and authorization
GitLab integrates with the following external authentication and authorization
-providers.
+providers:
-- [LDAP](ldap.md) Includes Active Directory, Apple Open Directory, Open LDAP,
- and 389 Server
+- [Auth0](../../integration/auth0.md)
+- [Authentiq](authentiq.md)
+- [Azure](../../integration/azure.md)
+- [Bitbucket Cloud](../../integration/bitbucket.md)
+- [CAS](../../integration/cas.md)
+- [Crowd](../../integration/crowd.md)
+- [Facebook](../../integration/facebook.md)
+- [GitHub](../../integration/github.md)
+- [GitLab.com](../../integration/gitlab.md)
+- [Google](../../integration/google.md)
+- [JWT](jwt.md)
+- [Kerberos](../../integration/kerberos.md)
+- [LDAP](ldap.md): Includes Active Directory, Apple Open Directory, Open LDAP,
+ and 389 Server.
- [LDAP for GitLab EE](ldap-ee.md): LDAP additions to GitLab Enterprise Editions **(STARTER ONLY)**
-- [OmniAuth](../../integration/omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google,
- Bitbucket, Facebook, Shibboleth, Crowd, Azure, Authentiq ID, and JWT
-- [CAS](../../integration/cas.md) Configure GitLab to sign in using CAS
-- [SAML](../../integration/saml.md) Configure GitLab as a SAML 2.0 Service Provider
-- [Okta](okta.md) Configure GitLab to sign in using Okta
-- [Authentiq](authentiq.md): Enable the Authentiq OmniAuth provider for passwordless authentication
-- [Smartcard](smartcard.md) Smartcard authentication **(PREMIUM ONLY)**
+ - [Google Secure LDAP](google_secure_ldap.md)
+- [Okta](okta.md)
+- [Salesforce](../../integration/salesforce.md)
+- [SAML](../../integration/saml.md)
+- [SAML for GitLab.com groups](../../user/group/saml_sso/index.md) **(SILVER ONLY)**
+- [Shibboleth](../../integration/shibboleth.md)
+- [Smartcard](smartcard.md) **(PREMIUM ONLY)**
+- [Twitter](../../integration/twitter.md)
+- [UltraAuth](../../integration/ultra_auth.md)
diff --git a/doc/administration/auth/authentiq.md b/doc/administration/auth/authentiq.md
index 726622d8599..b84eca4ef0d 100644
--- a/doc/administration/auth/authentiq.md
+++ b/doc/administration/auth/authentiq.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Authentiq OmniAuth Provider
To enable the Authentiq OmniAuth provider for passwordless authentication you must register an application with Authentiq.
@@ -8,47 +12,48 @@ Authentiq will generate a Client ID and the accompanying Client Secret for you t
1. On your GitLab server, open the configuration file:
- For omnibus installation
- ```sh
- sudo editor /etc/gitlab/gitlab.rb
- ```
+ For omnibus installation
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
- For installations from source:
+ For installations from source:
- ```sh
- sudo -u git -H editor /home/git/gitlab/config/gitlab.yml
- ```
+ ```sh
+ sudo -u git -H editor /home/git/gitlab/config/gitlab.yml
+ ```
1. See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration) for initial settings to enable single sign-on and add Authentiq as an OAuth provider.
1. Add the provider configuration for Authentiq:
- For Omnibus packages:
-
- ```ruby
- gitlab_rails['omniauth_providers'] = [
- {
- "name" => "authentiq",
- "app_id" => "YOUR_CLIENT_ID",
- "app_secret" => "YOUR_CLIENT_SECRET",
- "args" => {
- "scope": 'aq:name email~rs address aq:push'
- }
- }
- ]
- ```
-
- For installations from source:
-
- ```yaml
- - { name: 'authentiq',
- app_id: 'YOUR_CLIENT_ID',
- app_secret: 'YOUR_CLIENT_SECRET',
- args: {
- scope: 'aq:name email~rs address aq:push'
- }
- }
- ```
+ For Omnibus packages:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "authentiq",
+ "app_id" => "YOUR_CLIENT_ID",
+ "app_secret" => "YOUR_CLIENT_SECRET",
+ "args" => {
+ "scope": 'aq:name email~rs address aq:push'
+ }
+ }
+ ]
+ ```
+
+ For installations from source:
+
+ ```yaml
+ - { name: 'authentiq',
+ app_id: 'YOUR_CLIENT_ID',
+ app_secret: 'YOUR_CLIENT_SECRET',
+ args: {
+ scope: 'aq:name email~rs address aq:push'
+ }
+ }
+ ```
1. The `scope` is set to request the user's name, email (required and signed), and permission to send push notifications to sign in on subsequent visits.
See [OmniAuth Authentiq strategy](https://github.com/AuthentiqID/omniauth-authentiq/wiki/Scopes,-callback-url-configuration-and-responses) for more information on scopes and modifiers.
@@ -65,3 +70,15 @@ On the sign in page there should now be an Authentiq icon below the regular sign
- If not they will be prompted to download the app and then follow the procedure above.
If everything goes right, the user will be returned to GitLab and will be signed in.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/auth/crowd.md b/doc/administration/auth/crowd.md
index 6db74958d5a..ac63b4f2b97 100644
--- a/doc/administration/auth/crowd.md
+++ b/doc/administration/auth/crowd.md
@@ -1,60 +1,67 @@
+---
+type: reference
+---
+
# Atlassian Crowd OmniAuth Provider
+Authenticate to GitLab using the Atlassian Crowd OmniAuth provider.
+
## Configure a new Crowd application
1. Choose 'Applications' in the top menu, then 'Add application'.
1. Go through the 'Add application' steps, entering the appropriate details.
The screenshot below shows an example configuration.
- ![Example Crowd application configuration](img/crowd_application.png)
+ ![Example Crowd application configuration](img/crowd_application.png)
## Configure GitLab
1. On your GitLab server, open the configuration file.
- **Omnibus:**
+ **Omnibus:**
- ```sh
- sudo editor /etc/gitlab/gitlab.rb
- ```
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
- **Source:**
+ **Source:**
- ```sh
- cd /home/git/gitlab
+ ```sh
+ cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
- ```
+ sudo -u git -H editor config/gitlab.yml
+ ```
1. See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration)
for initial settings.
1. Add the provider configuration:
- **Omnibus:**
-
- ```ruby
- gitlab_rails['omniauth_providers'] = [
- {
- "name" => "crowd",
- "args" => {
- "crowd_server_url" => "CROWD_SERVER_URL",
- "application_name" => "YOUR_APP_NAME",
- "application_password" => "YOUR_APP_PASSWORD"
- }
- }
- ]
- ```
-
- **Source:**
-
- ```
- - { name: 'crowd',
- args: {
- crowd_server_url: 'CROWD_SERVER_URL',
- application_name: 'YOUR_APP_NAME',
- application_password: 'YOUR_APP_PASSWORD' } }
- ```
+ **Omnibus:**
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "crowd",
+ "args" => {
+ "crowd_server_url" => "CROWD_SERVER_URL",
+ "application_name" => "YOUR_APP_NAME",
+ "application_password" => "YOUR_APP_PASSWORD"
+ }
+ }
+ ]
+ ```
+
+ **Source:**
+
+ ```
+ - { name: 'crowd',
+ args: {
+ crowd_server_url: 'CROWD_SERVER_URL',
+ application_name: 'YOUR_APP_NAME',
+ application_password: 'YOUR_APP_PASSWORD' } }
+ ```
+
1. Change `CROWD_SERVER_URL` to the URL of your Crowd server.
1. Change `YOUR_APP_NAME` to the application name from Crowd applications page.
1. Change `YOUR_APP_PASSWORD` to the application password you've set.
@@ -77,4 +84,4 @@ could not authorize you from Crowd because invalid credentials
Please make sure the Crowd users who need to login to GitLab are authorized to [the application](#configure-a-new-crowd-application) in the step of **Authorisation**. This could be verified by try "Authentication test" for Crowd as of 2.11.
-![Example Crowd application authorisation configuration](img/crowd_application_authorisation.png) \ No newline at end of file
+![Example Crowd application authorisation configuration](img/crowd_application_authorisation.png)
diff --git a/doc/administration/auth/google_secure_ldap.md b/doc/administration/auth/google_secure_ldap.md
index 1db5bb4bc3f..55e6f53622c 100644
--- a/doc/administration/auth/google_secure_ldap.md
+++ b/doc/administration/auth/google_secure_ldap.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Google Secure LDAP **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/46391) in GitLab 11.9.
@@ -66,7 +70,7 @@ values obtained during the LDAP client configuration earlier:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
+ ```ruby
gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below
main: # 'main' is the GitLab 'provider ID' of this LDAP server
@@ -127,7 +131,7 @@ values obtained during the LDAP client configuration earlier:
AcZSFJQjdg5BTyvdEDhaYUKGdRw=
-----END PRIVATE KEY-----
EOS
- ```
+ ```
1. Save the file and [reconfigure] GitLab for the changes to take effect.
@@ -137,7 +141,7 @@ values obtained during the LDAP client configuration earlier:
1. Edit `config/gitlab.yml`:
- ```yaml
+ ```yaml
ldap:
enabled: true
servers:
@@ -204,3 +208,15 @@ values obtained during the LDAP client configuration earlier:
[reconfigure]: ../restart_gitlab.md#omnibus-gitlab-reconfigure
[restart]: ../restart_gitlab.md#installations-from-source
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
index 320a65b665d..86dd398343b 100644
--- a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
+++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
@@ -1,15 +1,9 @@
---
-author: Chris Wilson
-author_gitlab: MrChrisW
-level: intermediary
-article_type: admin guide
-date: 2017-05-03
+type: howto
---
# How to configure LDAP with GitLab CE
-## Introduction
-
Managing a large number of users in GitLab can become a burden for system administrators. As an organization grows so do user accounts. Keeping these user accounts in sync across multiple enterprise applications often becomes a time consuming task.
In this guide we will focus on configuring GitLab with Active Directory. [Active Directory](https://en.wikipedia.org/wiki/Active_Directory) is a popular LDAP compatible directory service provided by Microsoft, included in all modern Windows Server operating systems.
@@ -268,3 +262,15 @@ have extended functionalities with LDAP, such as:
- Multiple LDAP servers
Read through the article on [LDAP for GitLab EE](../how_to_configure_ldap_gitlab_ee/index.md) **(STARTER ONLY)** for an overview.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md b/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md
index 2683950f143..366acb9ed3e 100644
--- a/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md
+++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md
@@ -1,16 +1,10 @@
---
-author: Chris Wilson
-author_gitlab: MrChrisW
-level: intermediary
-article_type: admin guide
-date: 2017-05-03
+type: howto
---
# How to configure LDAP with GitLab EE **(STARTER ONLY)**
-## Introduction
-
-The present article follows [How to Configure LDAP with GitLab CE](../how_to_configure_ldap_gitlab_ce/index.md). Make sure to read through it before moving forward.
+This article expands on [How to Configure LDAP with GitLab CE](../how_to_configure_ldap_gitlab_ce/index.md). Make sure to read through it before moving forward.
## GitLab Enterprise Edition - LDAP features
@@ -117,3 +111,15 @@ Integration of GitLab with Active Directory (LDAP) reduces the complexity of use
It has the advantage of improving user permission controls, whilst easing the deployment of GitLab into an existing [IT environment](https://www.techopedia.com/definition/29199/it-infrastructure). GitLab EE offers advanced group management and multiple LDAP servers.
With the assistance of the [GitLab Support](https://about.gitlab.com/support) team, setting up GitLab with an existing AD/LDAP solution will be a smooth and painless process.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/auth/jwt.md b/doc/administration/auth/jwt.md
index 497298503ad..e6b3287ce60 100644
--- a/doc/administration/auth/jwt.md
+++ b/doc/administration/auth/jwt.md
@@ -1,67 +1,71 @@
+---
+type: reference
+---
+
# JWT OmniAuth provider
To enable the JWT OmniAuth provider, you must register your application with JWT.
JWT will provide you with a secret key for you to use.
-1. On your GitLab server, open the configuration file.
-
- For Omnibus GitLab:
-
- ```sh
- sudo editor /etc/gitlab/gitlab.rb
- ```
-
- For installations from source:
-
- ```sh
- cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
- ```
-
-1. See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration) for initial settings.
-1. Add the provider configuration.
-
- For Omnibus GitLab:
-
- ```ruby
- gitlab_rails['omniauth_providers'] = [
- { name: 'jwt',
- args: {
- secret: 'YOUR_APP_SECRET',
- algorithm: 'HS256', # Supported algorithms: 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512'
- uid_claim: 'email',
- required_claims: ['name', 'email'],
- info_maps: { name: 'name', email: 'email' },
- auth_url: 'https://example.com/',
- valid_within: 3600 # 1 hour
- }
- }
- ]
- ```
-
- For installation from source:
-
- ```
- - { name: 'jwt',
- args: {
- secret: 'YOUR_APP_SECRET',
- algorithm: 'HS256', # Supported algorithms: 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512'
- uid_claim: 'email',
- required_claims: ['name', 'email'],
- info_map: { name: 'name', email: 'email' },
- auth_url: 'https://example.com/',
- valid_within: 3600 # 1 hour
- }
- }
- ```
-
- NOTE: **Note:** For more information on each configuration option refer to
- the [OmniAuth JWT usage documentation](https://github.com/mbleigh/omniauth-jwt#usage).
-
-1. Change `YOUR_APP_SECRET` to the client secret and set `auth_url` to your redirect URL.
-1. Save the configuration file.
-1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you
- installed GitLab via Omnibus or from source respectively.
+1. On your GitLab server, open the configuration file.
+
+ For Omnibus GitLab:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For installations from source:
+
+ ```sh
+ cd /home/git/gitlab
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration) for initial settings.
+1. Add the provider configuration.
+
+ For Omnibus GitLab:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ { name: 'jwt',
+ args: {
+ secret: 'YOUR_APP_SECRET',
+ algorithm: 'HS256', # Supported algorithms: 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512'
+ uid_claim: 'email',
+ required_claims: ['name', 'email'],
+ info_maps: { name: 'name', email: 'email' },
+ auth_url: 'https://example.com/',
+ valid_within: 3600 # 1 hour
+ }
+ }
+ ]
+ ```
+
+ For installation from source:
+
+ ```
+ - { name: 'jwt',
+ args: {
+ secret: 'YOUR_APP_SECRET',
+ algorithm: 'HS256', # Supported algorithms: 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512'
+ uid_claim: 'email',
+ required_claims: ['name', 'email'],
+ info_map: { name: 'name', email: 'email' },
+ auth_url: 'https://example.com/',
+ valid_within: 3600 # 1 hour
+ }
+ }
+ ```
+
+ NOTE: **Note:** For more information on each configuration option refer to
+ the [OmniAuth JWT usage documentation](https://github.com/mbleigh/omniauth-jwt#usage).
+
+1. Change `YOUR_APP_SECRET` to the client secret and set `auth_url` to your redirect URL.
+1. Save the configuration file.
+1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you
+ installed GitLab via Omnibus or from source respectively.
On the sign in page there should now be a JWT icon below the regular sign in form.
Click the icon to begin the authentication process. JWT will ask the user to
@@ -70,3 +74,15 @@ will be redirected to GitLab and will be signed in.
[reconfigure]: ../restart_gitlab.md#omnibus-gitlab-reconfigure
[restart GitLab]: ../restart_gitlab.md#installations-from-source
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/auth/ldap-ee.md b/doc/administration/auth/ldap-ee.md
index 1a8af0827ee..2f2ee8a27d3 100644
--- a/doc/administration/auth/ldap-ee.md
+++ b/doc/administration/auth/ldap-ee.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# LDAP Additions in GitLab EE **(STARTER ONLY)**
This is a continuation of the main [LDAP documentation](ldap.md), detailing LDAP
@@ -85,19 +89,19 @@ following.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['ldap_servers'] = YAML.load <<-EOS
- main:
- ## snip...
- ##
- ## Base where we can search for groups
- ##
- ## Ex. ou=groups,dc=gitlab,dc=example
- ##
- ##
- group_base: ou=groups,dc=example,dc=com
- EOS
- ```
+ ```ruby
+ gitlab_rails['ldap_servers'] = YAML.load <<-EOS
+ main:
+ ## snip...
+ ##
+ ## Base where we can search for groups
+ ##
+ ## Ex. ou=groups,dc=gitlab,dc=example
+ ##
+ ##
+ group_base: ou=groups,dc=example,dc=com
+ EOS
+ ```
1. [Reconfigure GitLab][reconfigure] for the changes to take effect.
@@ -105,14 +109,14 @@ following.
1. Edit `/home/git/gitlab/config/gitlab.yml`:
- ```yaml
- production:
- ldap:
- servers:
- main:
- # snip...
- group_base: ou=groups,dc=example,dc=com
- ```
+ ```yaml
+ production:
+ ldap:
+ servers:
+ main:
+ # snip...
+ group_base: ou=groups,dc=example,dc=com
+ ```
1. [Restart GitLab][restart] for the changes to take effect.
@@ -140,30 +144,30 @@ group, as opposed to the full DN.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['ldap_servers'] = YAML.load <<-EOS
- main:
- ## snip...
- ##
- ## Base where we can search for groups
- ##
- ## Ex. ou=groups,dc=gitlab,dc=example
- ##
- ##
- group_base: ou=groups,dc=example,dc=com
-
- ##
- ## The CN of a group containing GitLab administrators
- ##
- ## Ex. administrators
- ##
- ## Note: Not `cn=administrators` or the full DN
- ##
- ##
- admin_group: my_admin_group
-
- EOS
- ```
+ ```ruby
+ gitlab_rails['ldap_servers'] = YAML.load <<-EOS
+ main:
+ ## snip...
+ ##
+ ## Base where we can search for groups
+ ##
+ ## Ex. ou=groups,dc=gitlab,dc=example
+ ##
+ ##
+ group_base: ou=groups,dc=example,dc=com
+
+ ##
+ ## The CN of a group containing GitLab administrators
+ ##
+ ## Ex. administrators
+ ##
+ ## Note: Not `cn=administrators` or the full DN
+ ##
+ ##
+ admin_group: my_admin_group
+
+ EOS
+ ```
1. [Reconfigure GitLab][reconfigure] for the changes to take effect.
@@ -171,15 +175,15 @@ group, as opposed to the full DN.
1. Edit `/home/git/gitlab/config/gitlab.yml`:
- ```yaml
- production:
- ldap:
- servers:
- main:
- # snip...
- group_base: ou=groups,dc=example,dc=com
- admin_group: my_admin_group
- ```
+ ```yaml
+ production:
+ ldap:
+ servers:
+ main:
+ # snip...
+ group_base: ou=groups,dc=example,dc=com
+ admin_group: my_admin_group
+ ```
1. [Restart GitLab][restart] for the changes to take effect.
@@ -191,7 +195,6 @@ to lock down user abilities to invite new members to a group. When enabled follo
1. Only administrator can manage memberships of any group including access levels.
2. Users are not allowed to share project with other groups or invite members to a project created in a group.
-
## Adjusting LDAP user sync schedule
> Introduced in GitLab Enterprise Edition Starter.
@@ -211,9 +214,9 @@ sync to run once every 12 hours at the top of the hour.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['ldap_sync_worker_cron'] = "0 */12 * * *"
- ```
+ ```ruby
+ gitlab_rails['ldap_sync_worker_cron'] = "0 */12 * * *"
+ ```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
@@ -221,11 +224,11 @@ sync to run once every 12 hours at the top of the hour.
1. Edit `config/gitlab.yaml`:
- ```yaml
- cron_jobs:
- ldap_sync_worker_cron:
- "0 */12 * * *"
- ```
+ ```yaml
+ cron_jobs:
+ ldap_sync_worker_cron:
+ "0 */12 * * *"
+ ```
1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
@@ -252,9 +255,9 @@ sync to run once every 2 hours at the top of the hour.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * * *"
- ```
+ ```ruby
+ gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * * *"
+ ```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
@@ -262,11 +265,11 @@ sync to run once every 2 hours at the top of the hour.
1. Edit `config/gitlab.yaml`:
- ```yaml
- cron_jobs:
- ldap_group_sync_worker_cron:
- "*/30 * * * *"
- ```
+ ```yaml
+ cron_jobs:
+ ldap_group_sync_worker_cron:
+ "*/30 * * * *"
+ ```
1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
@@ -283,20 +286,20 @@ task.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['ldap_servers'] = YAML.load <<-EOS
- main:
- ## snip...
- ##
- ## An array of CNs of groups containing users that should be considered external
- ##
- ## Ex. ['interns', 'contractors']
- ##
- ## Note: Not `cn=interns` or the full DN
- ##
- external_groups: ['interns', 'contractors']
- EOS
- ```
+ ```ruby
+ gitlab_rails['ldap_servers'] = YAML.load <<-EOS
+ main:
+ ## snip...
+ ##
+ ## An array of CNs of groups containing users that should be considered external
+ ##
+ ## Ex. ['interns', 'contractors']
+ ##
+ ## Note: Not `cn=interns` or the full DN
+ ##
+ external_groups: ['interns', 'contractors']
+ EOS
+ ```
1. [Reconfigure GitLab][reconfigure] for the changes to take effect.
@@ -304,14 +307,14 @@ task.
1. Edit `config/gitlab.yaml`:
- ```yaml
- production:
- ldap:
- servers:
- main:
- # snip...
- external_groups: ['interns', 'contractors']
- ```
+ ```yaml
+ production:
+ ldap:
+ servers:
+ main:
+ # snip...
+ external_groups: ['interns', 'contractors']
+ ```
1. [Restart GitLab][restart] for the changes to take effect.
@@ -436,66 +439,71 @@ step of the sync.
1. Start a Rails console
- ```bash
- # For Omnibus installations
- sudo gitlab-rails console
+ ```bash
+ # For Omnibus installations
+ sudo gitlab-rails console
- # For installations from source
- sudo -u git -H bundle exec rails console production
- ```
+ # For installations from source
+ sudo -u git -H bundle exec rails console production
+ ```
1. Set the log level to debug (only for this session):
- ```ruby
- Rails.logger.level = Logger::DEBUG
- ```
+ ```ruby
+ Rails.logger.level = Logger::DEBUG
+ ```
+
1. Choose a GitLab group to test with. This group should have an LDAP group link
already configured. If the output is `nil`, the group could not be found.
If a bunch of group attributes are output, your group was found successfully.
- ```ruby
- group = Group.find_by(name: 'my_group')
+ ```ruby
+ group = Group.find_by(name: 'my_group')
+
+ # Output
+ => #<Group:0x007fe825196558 id: 1234, name: "my_group"...>
+ ```
- # Output
- => #<Group:0x007fe825196558 id: 1234, name: "my_group"...>
- ```
1. Run a group sync for this particular group.
- ```ruby
- EE::Gitlab::Auth::LDAP::Sync::Group.execute_all_providers(group)
- ```
+ ```ruby
+ EE::Gitlab::Auth::LDAP::Sync::Group.execute_all_providers(group)
+ ```
+
1. Look through the output of the sync. See [example log output](#example-log-output)
below for more information about the output.
1. If you still aren't able to see why the user isn't being added, query the
LDAP group directly to see what members are listed. Still in the Rails console,
run the following query:
- ```ruby
- adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider
- ldap_group = EE::Gitlab::Auth::LDAP::Group.find_by_cn('group_cn_here', adapter)
+ ```ruby
+ adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider
+ ldap_group = EE::Gitlab::Auth::LDAP::Group.find_by_cn('group_cn_here', adapter)
+
+ # Output
+ => #<EE::Gitlab::Auth::LDAP::Group:0x007fcbdd0bb6d8
+ ```
- # Output
- => #<EE::Gitlab::Auth::LDAP::Group:0x007fcbdd0bb6d8
- ```
1. Query the LDAP group's member DNs and see if the user's DN is in the list.
One of the DNs here should match the 'Identifier' from the LDAP identity
checked earlier. If it doesn't, the user does not appear to be in the LDAP
group.
- ```ruby
- ldap_group.member_dns
+ ```ruby
+ ldap_group.member_dns
+
+ # Output
+ => ["uid=john,ou=people,dc=example,dc=com", "uid=mary,ou=people,dc=example,dc=com"]
+ ```
- # Output
- => ["uid=john,ou=people,dc=example,dc=com", "uid=mary,ou=people,dc=example,dc=com"]
- ```
1. Some LDAP servers don't store members by DN. Rather, they use UIDs instead.
If you didn't see results from the last query, try querying by UIDs instead.
- ```ruby
- ldap_group.member_uids
+ ```ruby
+ ldap_group.member_uids
- # Output
- => ['john','mary']
- ```
+ # Output
+ => ['john','mary']
+ ```
#### Example log output
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index 2144f5753a8..be05a4d63a7 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
<!-- If the change is EE-specific, put it in `ldap-ee.md`, NOT here. -->
# LDAP
@@ -398,30 +402,30 @@ The `user_filter` DN can contain special characters. For example:
- A comma:
- ```
- OU=GitLab, Inc,DC=gitlab,DC=com
- ```
+ ```
+ OU=GitLab, Inc,DC=gitlab,DC=com
+ ```
- Open and close brackets:
- ```
- OU=Gitlab (Inc),DC=gitlab,DC=com
- ```
+ ```
+ OU=Gitlab (Inc),DC=gitlab,DC=com
+ ```
- These characters must be escaped as documented in
- [RFC 4515](https://tools.ietf.org/search/rfc4515).
+ These characters must be escaped as documented in
+ [RFC 4515](https://tools.ietf.org/search/rfc4515).
- Escape commas with `\2C`. For example:
- ```
- OU=GitLab\2C Inc,DC=gitlab,DC=com
- ```
+ ```
+ OU=GitLab\2C Inc,DC=gitlab,DC=com
+ ```
- Escape open and close brackets with `\28` and `\29`, respectively. For example:
- ```
- OU=Gitlab \28Inc\29,DC=gitlab,DC=com
- ```
+ ```
+ OU=Gitlab \28Inc\29,DC=gitlab,DC=com
+ ```
## Enabling LDAP sign-in for existing GitLab users
@@ -445,13 +449,13 @@ the configuration option `lowercase_usernames`. By default, this configuration o
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['ldap_servers'] = YAML.load <<-EOS
- main:
- # snip...
- lowercase_usernames: true
- EOS
- ```
+ ```ruby
+ gitlab_rails['ldap_servers'] = YAML.load <<-EOS
+ main:
+ # snip...
+ lowercase_usernames: true
+ EOS
+ ```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
@@ -459,14 +463,14 @@ the configuration option `lowercase_usernames`. By default, this configuration o
1. Edit `config/gitlab.yaml`:
- ```yaml
- production:
- ldap:
- servers:
- main:
- # snip...
- lowercase_usernames: true
- ```
+ ```yaml
+ production:
+ ldap:
+ servers:
+ main:
+ # snip...
+ lowercase_usernames: true
+ ```
1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
@@ -494,6 +498,13 @@ be mandatory and clients cannot be authenticated with the TLS protocol.
## Troubleshooting
+If a user account is blocked or unblocked due to the LDAP configuration, a
+message will be logged to `application.log`.
+
+If there is an unexpected error during an LDAP lookup (configuration error,
+timeout), the login is rejected and a message will be logged to
+`production.log`.
+
### Debug LDAP user filter with ldapsearch
This example uses ldapsearch and assumes you are using ActiveDirectory. The
@@ -519,26 +530,17 @@ ldapsearch -H ldaps://$host:$port -D "$bind_dn" -y bind_dn_password.txt -b "$ba
- Run the following check command to make sure that the LDAP settings are
correct and GitLab can see your users:
- ```bash
- # For Omnibus installations
- sudo gitlab-rake gitlab:ldap:check
+ ```bash
+ # For Omnibus installations
+ sudo gitlab-rake gitlab:ldap:check
- # For installations from source
- sudo -u git -H bundle exec rake gitlab:ldap:check RAILS_ENV=production
- ```
+ # For installations from source
+ sudo -u git -H bundle exec rake gitlab:ldap:check RAILS_ENV=production
+ ```
-### Connection Refused
+### Connection refused
If you are getting 'Connection Refused' errors when trying to connect to the
LDAP server please double-check the LDAP `port` and `encryption` settings used by
GitLab. Common combinations are `encryption: 'plain'` and `port: 389`, OR
`encryption: 'simple_tls'` and `port: 636`.
-
-### Troubleshooting
-
-If a user account is blocked or unblocked due to the LDAP configuration, a
-message will be logged to `application.log`.
-
-If there is an unexpected error during an LDAP lookup (configuration error,
-timeout), the login is rejected and a message will be logged to
-`production.log`.
diff --git a/doc/administration/auth/oidc.md b/doc/administration/auth/oidc.md
index 6e48add6930..78d040cda99 100644
--- a/doc/administration/auth/oidc.md
+++ b/doc/administration/auth/oidc.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# OpenID Connect OmniAuth provider
GitLab can use [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) as an OmniAuth provider.
@@ -5,82 +9,89 @@ GitLab can use [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0
To enable the OpenID Connect OmniAuth provider, you must register your application with an OpenID Connect provider.
The OpenID Connect will provide you with a client details and secret for you to use.
-1. On your GitLab server, open the configuration file.
-
- For Omnibus GitLab:
-
- ```sh
- sudo editor /etc/gitlab/gitlab.rb
- ```
-
- For installations from source:
-
- ```sh
- cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
- ```
-
- See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration) for initial settings.
-
-1. Add the provider configuration.
-
- For Omnibus GitLab:
-
- ```ruby
- gitlab_rails['omniauth_providers'] = [
- { 'name' => 'openid_connect',
- 'label' => '<your_oidc_label>',
- 'args' => {
- "name' => 'openid_connect',
- 'scope' => ['openid','profile'],
- 'response_type' => 'code',
- 'issuer' => '<your_oidc_url>',
- 'discovery' => true,
- 'client_auth_method' => 'query',
- 'uid_field' => '<uid_field>',
- 'client_options' => {
- 'identifier' => '<your_oidc_client_id>',
- 'secret' => '<your_oidc_client_secret>',
- 'redirect_uri' => '<your_gitlab_url>/users/auth/openid_connect/callback'
- }
- }
- }
- ]
- ```
-
- For installation from source:
-
- ```yaml
- - { name: 'openid_connect',
- label: '<your_oidc_label>',
- args: {
- name: 'openid_connect',
- scope: ['openid','profile'],
- response_type: 'code',
- issuer: '<your_oidc_url>',
- discovery: true,
- client_auth_method: 'query',
- uid_field: '<uid_field>',
- client_options: {
- identifier: '<your_oidc_client_id>',
- secret: '<your_oidc_client_secret>',
- redirect_uri: '<your_gitlab_url>/users/auth/openid_connect/callback'
- }
- }
- }
- ```
-
- > **Note:**
- >
- > - For more information on each configuration option refer to
- the [OmniAuth OpenID Connect usage documentation](https://github.com/m0n9oose/omniauth_openid_connect#usage) and
- the [OpenID Connect Core 1.0 specification](https://openid.net/specs/openid-connect-core-1_0.html).
+1. On your GitLab server, open the configuration file.
+
+ For Omnibus GitLab:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For installations from source:
+
+ ```sh
+ cd /home/git/gitlab
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+ See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration.
+
+ For Omnibus GitLab:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ { 'name' => 'openid_connect',
+ 'label' => '<your_oidc_label>',
+ 'args' => {
+ "name' => 'openid_connect',
+ 'scope' => ['openid','profile'],
+ 'response_type' => 'code',
+ 'issuer' => '<your_oidc_url>',
+ 'discovery' => true,
+ 'client_auth_method' => 'query',
+ 'uid_field' => '<uid_field>',
+ 'client_options' => {
+ 'identifier' => '<your_oidc_client_id>',
+ 'secret' => '<your_oidc_client_secret>',
+ 'redirect_uri' => '<your_gitlab_url>/users/auth/openid_connect/callback'
+ }
+ }
+ }
+ ]
+ ```
+
+ For installation from source:
+
+ ```yaml
+ - { name: 'openid_connect',
+ label: '<your_oidc_label>',
+ args: {
+ name: 'openid_connect',
+ scope: ['openid','profile'],
+ response_type: 'code',
+ issuer: '<your_oidc_url>',
+ discovery: true,
+ client_auth_method: 'query',
+ uid_field: '<uid_field>',
+ client_options: {
+ identifier: '<your_oidc_client_id>',
+ secret: '<your_oidc_client_secret>',
+ redirect_uri: '<your_gitlab_url>/users/auth/openid_connect/callback'
+ }
+ }
+ }
+ ```
+
+ > **Note:**
+ >
+ > - For more information on each configuration option refer to
+ the [OmniAuth OpenID Connect usage documentation](https://github.com/m0n9oose/omniauth_openid_connect#usage) and
+ the [OpenID Connect Core 1.0 specification](https://openid.net/specs/openid-connect-core-1_0.html).
1. For the configuration above, change the values for the provider to match your OpenID Connect client setup. Use the following as a guide:
- `<your_oidc_label>` is the label that will be displayed on the login page.
- `<your_oidc_url>` (optional) is the URL that points to the OpenID Connect provider. For example, `https://example.com/auth/realms/your-realm`.
If this value is not provided, the URL is constructed from the `client_options` in the following format: `<client_options.scheme>://<client_options.host>:<client_options.port>`.
- If `discovery` is set to `true`, the OpenID Connect provider will try to auto discover the client options using `<your_oidc_url>/.well-known/openid-configuration`. Defaults to `false`.
+ - `client_auth_method` (optional) specifies the method used for authenticating the client with the OpenID Connect provider.
+ - Supported values are:
+ - `basic` - HTTP Basic Authentication
+ - `jwt_bearer` - JWT based authentication (private key and client secret signing)
+ - `mtls` - Mutual TLS or X.509 certificate validation
+ - Any other value will POST the client id and secret in the request body
+ - If not specified, defaults to `basic`.
- `<uid_field>` (optional) is the field name from the `user_info` details that will be used as `uid` value. For example, `preferred_username`.
If this value is not provided or the field with the configured value is missing from the `user_info` details, the `uid` will use the `sub` field.
- `client_options` are the OpenID Connect client-specific options. Specifically:
@@ -139,7 +150,7 @@ for more details:
}
```
-### Troubleshooting
+## Troubleshooting
If you're having trouble, here are some tips:
@@ -155,9 +166,9 @@ If you're having trouble, here are some tips:
`https://accounts.google.com/.well-known/openid-configuration`.
1. The OpenID Connect client uses HTTP Basic Authentication to send the
- OAuth2 access token. For example, if you are seeing 401 errors upon
- retrieving the `userinfo` endpoint, you may want to check your OpenID
- Web server configuration. For example, for
+ OAuth2 access token if `client_auth_method` is not defined or if set to `basic`.
+ If you are seeing 401 errors upon retrieving the `userinfo` endpoint, you may
+ want to check your OpenID Web server configuration. For example, for
[oauth2-server-php](https://github.com/bshaffer/oauth2-server-php), you
may need to [add a configuration parameter to
Apache](https://github.com/bshaffer/oauth2-server-php/issues/926#issuecomment-387502778).
diff --git a/doc/administration/auth/okta.md b/doc/administration/auth/okta.md
index aa4e1b0d2e0..5524c3ba092 100644
--- a/doc/administration/auth/okta.md
+++ b/doc/administration/auth/okta.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Okta SSO provider
Okta is a [Single Sign-on provider](https://www.okta.com/products/single-sign-on/) that can be used to authenticate
@@ -16,7 +20,7 @@ The following documentation enables Okta as a SAML provider.
1. Next, you'll need the to fill in the SAML general config. Here's an example
image.
- ![Okta admin panel view](img/okta_admin_panel.png)
+ ![Okta admin panel view](img/okta_admin_panel.png)
1. The last part of the configuration is the feedback section where you can
just say you're a customer and creating an app for internal use.
@@ -24,7 +28,7 @@ The following documentation enables Okta as a SAML provider.
profile. Click on the SAML 2.0 config instructions button which should
look like the following:
- ![Okta SAML settings](img/okta_saml_settings.png)
+ ![Okta SAML settings](img/okta_saml_settings.png)
1. On the screen that comes up take note of the
**Identity Provider Single Sign-On URL** which you'll use for the
@@ -38,112 +42,112 @@ Now that the Okta app is configured, it's time to enable it in GitLab.
## Configure GitLab
-1. On your GitLab server, open the configuration file:
-
- **For Omnibus GitLab installations**
-
- ```sh
- sudo editor /etc/gitlab/gitlab.rb
- ```
-
- **For installations from source**
-
- ```sh
- cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
- ```
-
-1. See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration)
- for initial settings.
-
-1. To allow your users to use Okta to sign up without having to manually create
- an account first, don't forget to add the following values to your
- configuration:
-
- **For Omnibus GitLab installations**
-
- ```ruby
- gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
- gitlab_rails['omniauth_block_auto_created_users'] = false
- ```
-
- **For installations from source**
-
- ```yaml
- allow_single_sign_on: ["saml"]
- block_auto_created_users: false
- ```
-
-1. You can also automatically link Okta users with existing GitLab users if
- their email addresses match by adding the following setting:
-
- **For Omnibus GitLab installations**
-
- ```ruby
- gitlab_rails['omniauth_auto_link_saml_user'] = true
- ```
-
- **For installations from source**
-
- ```yaml
- auto_link_saml_user: true
- ```
-
-1. Add the provider configuration.
-
- >**Notes:**
- >
- >- Change the value for `assertion_consumer_service_url` to match the HTTPS endpoint
- of GitLab (append `users/auth/saml/callback` to the HTTPS URL of your GitLab
- installation to generate the correct value).
- >
- >- To get the `idp_cert_fingerprint` fingerprint, first download the
- certificate from the Okta app you registered and then run:
- `openssl x509 -in okta.cert -noout -fingerprint`. Substitute `okta.cert`
- with the location of your certificate.
- >
- >- Change the value of `idp_sso_target_url`, with the value of the
- **Identity Provider Single Sign-On URL** from the step when you
- configured the Okta app.
- >
- >- Change the value of `issuer` to the value of the **Audience Restriction** from your Okta app configuration. This will identify GitLab
- to the IdP.
- >
- >- Leave `name_identifier_format` as-is.
-
- **For Omnibus GitLab installations**
-
- ```ruby
- gitlab_rails['omniauth_providers'] = [
- {
- name: 'saml',
- args: {
- assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
- idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
- idp_sso_target_url: 'https://gitlab.oktapreview.com/app/gitlabdev773716_gitlabsaml_1/exk8odl81tBrjpD4B0h7/sso/saml',
- issuer: 'https://gitlab.example.com',
- name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
- },
- label: 'Okta' # optional label for SAML login button, defaults to "Saml"
- }
- ]
- ```
-
- **For installations from source**
-
- ```yaml
- - {
- name: 'saml',
- args: {
- assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
- idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
- idp_sso_target_url: 'https://gitlab.oktapreview.com/app/gitlabdev773716_gitlabsaml_1/exk8odl81tBrjpD4B0h7/sso/saml',
- issuer: 'https://gitlab.example.com',
- name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
- },
- label: 'Okta' # optional label for SAML login button, defaults to "Saml"
- }
- ```
+1. On your GitLab server, open the configuration file:
+
+ **For Omnibus GitLab installations**
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ **For installations from source**
+
+ ```sh
+ cd /home/git/gitlab
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. See [Initial OmniAuth Configuration](../../integration/omniauth.md#initial-omniauth-configuration)
+ for initial settings.
+
+1. To allow your users to use Okta to sign up without having to manually create
+ an account first, don't forget to add the following values to your
+ configuration:
+
+ **For Omnibus GitLab installations**
+
+ ```ruby
+ gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
+ gitlab_rails['omniauth_block_auto_created_users'] = false
+ ```
+
+ **For installations from source**
+
+ ```yaml
+ allow_single_sign_on: ["saml"]
+ block_auto_created_users: false
+ ```
+
+1. You can also automatically link Okta users with existing GitLab users if
+ their email addresses match by adding the following setting:
+
+ **For Omnibus GitLab installations**
+
+ ```ruby
+ gitlab_rails['omniauth_auto_link_saml_user'] = true
+ ```
+
+ **For installations from source**
+
+ ```yaml
+ auto_link_saml_user: true
+ ```
+
+1. Add the provider configuration.
+
+ >**Notes:**
+ >
+ >- Change the value for `assertion_consumer_service_url` to match the HTTPS endpoint
+ of GitLab (append `users/auth/saml/callback` to the HTTPS URL of your GitLab
+ installation to generate the correct value).
+ >
+ >- To get the `idp_cert_fingerprint` fingerprint, first download the
+ certificate from the Okta app you registered and then run:
+ `openssl x509 -in okta.cert -noout -fingerprint`. Substitute `okta.cert`
+ with the location of your certificate.
+ >
+ >- Change the value of `idp_sso_target_url`, with the value of the
+ **Identity Provider Single Sign-On URL** from the step when you
+ configured the Okta app.
+ >
+ >- Change the value of `issuer` to the value of the **Audience Restriction** from your Okta app configuration. This will identify GitLab
+ to the IdP.
+ >
+ >- Leave `name_identifier_format` as-is.
+
+ **For Omnibus GitLab installations**
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ name: 'saml',
+ args: {
+ assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
+ idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
+ idp_sso_target_url: 'https://gitlab.oktapreview.com/app/gitlabdev773716_gitlabsaml_1/exk8odl81tBrjpD4B0h7/sso/saml',
+ issuer: 'https://gitlab.example.com',
+ name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
+ },
+ label: 'Okta' # optional label for SAML login button, defaults to "Saml"
+ }
+ ]
+ ```
+
+ **For installations from source**
+
+ ```yaml
+ - {
+ name: 'saml',
+ args: {
+ assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
+ idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
+ idp_sso_target_url: 'https://gitlab.oktapreview.com/app/gitlabdev773716_gitlabsaml_1/exk8odl81tBrjpD4B0h7/sso/saml',
+ issuer: 'https://gitlab.example.com',
+ name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
+ },
+ label: 'Okta' # optional label for SAML login button, defaults to "Saml"
+ }
+ ```
1. [Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) or [restart](../restart_gitlab.md#installations-from-source) GitLab for Omnibus and installations
from source respectively for the changes to take effect.
@@ -157,3 +161,15 @@ Make sure the groups exist and are assigned to the Okta app.
You can take a look of the [SAML documentation](../../integration/saml.md#marking-users-as-external-based-on-saml-groups) on external groups since
it works the same.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/auth/smartcard.md b/doc/administration/auth/smartcard.md
index a0d4e9ef3b5..4f236d1afb8 100644
--- a/doc/administration/auth/smartcard.md
+++ b/doc/administration/auth/smartcard.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Smartcard authentication **(PREMIUM ONLY)**
GitLab supports authentication using smartcards.
@@ -22,7 +26,7 @@ To use a smartcard with an X.509 certificate to authenticate against a local
database with GitLab, `CN` and `emailAddress` must be defined in the
certificate. For example:
-```
+```text
Certificate:
Data:
Version: 1 (0x0)
@@ -56,11 +60,11 @@ attribute. As a prerequisite, you must use an LDAP server that:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['smartcard_enabled'] = true
- gitlab_rails['smartcard_ca_file'] = "/etc/ssl/certs/CA.pem"
- gitlab_rails['smartcard_client_certificate_required_port'] = 3444
- ```
+ ```ruby
+ gitlab_rails['smartcard_enabled'] = true
+ gitlab_rails['smartcard_ca_file'] = "/etc/ssl/certs/CA.pem"
+ gitlab_rails['smartcard_client_certificate_required_port'] = 3444
+ ```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
GitLab for the changes to take effect.
@@ -154,15 +158,15 @@ attribute. As a prerequisite, you must use an LDAP server that:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['ldap_servers'] = YAML.load <<-EOS
- main:
- # snip...
- # Enable smartcard authentication against the LDAP server. Valid values
- # are "false", "optional", and "required".
- smartcard_auth: optional
- EOS
- ```
+ ```ruby
+ gitlab_rails['ldap_servers'] = YAML.load <<-EOS
+ main:
+ # snip...
+ # Enable smartcard authentication against the LDAP server. Valid values
+ # are "false", "optional", and "required".
+ smartcard_auth: optional
+ EOS
+ ```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
GitLab for the changes to take effect.
@@ -171,16 +175,16 @@ attribute. As a prerequisite, you must use an LDAP server that:
1. Edit `config/gitlab.yml`:
- ```yaml
- production:
- ldap:
- servers:
- main:
- # snip...
- # Enable smartcard authentication against the LDAP server. Valid values
- # are "false", "optional", and "required".
- smartcard_auth: optional
- ```
+ ```yaml
+ production:
+ ldap:
+ servers:
+ main:
+ # snip...
+ # Enable smartcard authentication against the LDAP server. Valid values
+ # are "false", "optional", and "required".
+ smartcard_auth: optional
+ ```
1. Save the file and [restart](../restart_gitlab.md#installations-from-source)
GitLab for the changes to take effect.
@@ -191,9 +195,9 @@ attribute. As a prerequisite, you must use an LDAP server that:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['smartcard_required_for_git_access'] = true
- ```
+ ```ruby
+ gitlab_rails['smartcard_required_for_git_access'] = true
+ ```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
GitLab for the changes to take effect.
@@ -202,13 +206,25 @@ attribute. As a prerequisite, you must use an LDAP server that:
1. Edit `config/gitlab.yml`:
- ```yaml
- ## Smartcard authentication settings
- smartcard:
- # snip...
- # Browser session with smartcard sign-in is required for Git access
- required_for_git_access: true
- ```
+ ```yaml
+ ## Smartcard authentication settings
+ smartcard:
+ # snip...
+ # Browser session with smartcard sign-in is required for Git access
+ required_for_git_access: true
+ ```
1. Save the file and [restart](../restart_gitlab.md#installations-from-source)
GitLab for the changes to take effect.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md
index 04f52783d22..3e3054af509 100644
--- a/doc/administration/container_registry.md
+++ b/doc/administration/container_registry.md
@@ -696,12 +696,11 @@ project or branch name. Special characters can include:
- Trailing hyphen/dash
- Double hyphen/dash
-To get around this, you can [change the group path](../user/group/index.md#changing-a-groups-path),
-[change the project path](../user/project/settings/index.md#renaming-a-repository) or change the
-branch name. Another option is to create a [push rule](../push_rules/push_rules.html) to prevent
+To get around this, you can [change the group path](../user/group/index.md#changing-a-groups-path),
+[change the project path](../user/project/settings/index.md#renaming-a-repository) or change the
+branch name. Another option is to create a [push rule](../push_rules/push_rules.html) to prevent
this at the instance level.
-
[ce-18239]: https://gitlab.com/gitlab-org/gitlab-ce/issues/18239
[docker-insecure-self-signed]: https://docs.docker.com/registry/insecure/#use-self-signed-certificates
[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
diff --git a/doc/administration/dependency_proxy.md b/doc/administration/dependency_proxy.md
index 776c60703fc..d2c52b67e67 100644
--- a/doc/administration/dependency_proxy.md
+++ b/doc/administration/dependency_proxy.md
@@ -70,6 +70,7 @@ To change the local storage path:
enabled: true
storage_path: shared/dependency_proxy
```
+
1. [Restart GitLab] for the changes to take effect.
### Using object storage
diff --git a/doc/administration/geo/disaster_recovery/bring_primary_back.md b/doc/administration/geo/disaster_recovery/bring_primary_back.md
index 30d35df25c7..64d7ef2d609 100644
--- a/doc/administration/geo/disaster_recovery/bring_primary_back.md
+++ b/doc/administration/geo/disaster_recovery/bring_primary_back.md
@@ -30,7 +30,7 @@ To bring the former **primary** node up to date:
`sudo systemctl enable gitlab-runsvdir`. For CentOS 6, you need to install
the GitLab instance from scratch and set it up as a **secondary** node by
following [Setup instructions][setup-geo]. In this case, you don't need to follow the next step.
-
+
NOTE: **Note:** If you [changed the DNS records](index.md#step-4-optional-updating-the-primary-domain-dns-record)
for this node during disaster recovery procedure you may need to [block
all the writes to this node](planned_failover.md#prevent-updates-to-the-primary-node)
diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md
index 393326c3347..0c2d48854f0 100644
--- a/doc/administration/geo/disaster_recovery/planned_failover.md
+++ b/doc/administration/geo/disaster_recovery/planned_failover.md
@@ -187,7 +187,7 @@ access to the **primary** node during the maintenance window.
before it is completed will cause the work to be lost.
1. On the **primary** node, navigate to **Admin Area > Geo** and wait for the
following conditions to be true of the **secondary** node you are failing over to:
-
+
- All replication meters to each 100% replicated, 0% failures.
- All verification meters reach 100% verified, 0% failures.
- Database replication lag is 0ms.
diff --git a/doc/administration/geo/replication/database.md b/doc/administration/geo/replication/database.md
index 71a1ce87833..9272287a4a7 100644
--- a/doc/administration/geo/replication/database.md
+++ b/doc/administration/geo/replication/database.md
@@ -116,7 +116,7 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
by default. However, Geo requires the **secondary** node to be able to
connect to the **primary** node's database. For this reason, we need the address of
each node.
-
+
NOTE: **Note:** For external PostgreSQL instances, see [additional instructions](external_database.md).
If you are using a cloud provider, you can lookup the addresses for each
@@ -424,22 +424,22 @@ data before running `pg_basebackup`.
- If PostgreSQL is listening on a non-standard port, add `--port=` as well.
- If your database is too large to be transferred in 30 minutes, you will need
- to increase the timeout, e.g., `--backup-timeout=3600` if you expect the
- initial replication to take under an hour.
- - Pass `--sslmode=disable` to skip PostgreSQL TLS authentication altogether
- (e.g., you know the network path is secure, or you are using a site-to-site
- VPN). This is **not** safe over the public Internet!
- - You can read more details about each `sslmode` in the
- [PostgreSQL documentation][pg-docs-ssl];
- the instructions above are carefully written to ensure protection against
- both passive eavesdroppers and active "man-in-the-middle" attackers.
- - Change the `--slot-name` to the name of the replication slot
- to be used on the **primary** database. The script will attempt to create the
- replication slot automatically if it does not exist.
- - If you're repurposing an old server into a Geo **secondary** node, you'll need to
- add `--force` to the command line.
- - When not in a production machine you can disable backup step if you
- really sure this is what you want by adding `--skip-backup`
+ to increase the timeout, e.g., `--backup-timeout=3600` if you expect the
+ initial replication to take under an hour.
+ - Pass `--sslmode=disable` to skip PostgreSQL TLS authentication altogether
+ (e.g., you know the network path is secure, or you are using a site-to-site
+ VPN). This is **not** safe over the public Internet!
+ - You can read more details about each `sslmode` in the
+ [PostgreSQL documentation][pg-docs-ssl];
+ the instructions above are carefully written to ensure protection against
+ both passive eavesdroppers and active "man-in-the-middle" attackers.
+ - Change the `--slot-name` to the name of the replication slot
+ to be used on the **primary** database. The script will attempt to create the
+ replication slot automatically if it does not exist.
+ - If you're repurposing an old server into a Geo **secondary** node, you'll need to
+ add `--force` to the command line.
+ - When not in a production machine you can disable backup step if you
+ really sure this is what you want by adding `--skip-backup`
The replication process is now complete.
diff --git a/doc/administration/geo/replication/external_database.md b/doc/administration/geo/replication/external_database.md
index 85687d4a648..256195998a7 100644
--- a/doc/administration/geo/replication/external_database.md
+++ b/doc/administration/geo/replication/external_database.md
@@ -25,7 +25,6 @@ developed and tested. We aim to be compatible with most external
This command will use your defined `external_url` in `/etc/gitlab/gitlab.rb`.
-
### Configure the external database to be replicated
To set up an external database, you can either:
diff --git a/doc/administration/geo/replication/remove_geo_node.md b/doc/administration/geo/replication/remove_geo_node.md
index 4f64e21f8ef..e24eb2bd428 100644
--- a/doc/administration/geo/replication/remove_geo_node.md
+++ b/doc/administration/geo/replication/remove_geo_node.md
@@ -19,10 +19,10 @@ Once removed from the Geo admin page, you must stop and uninstall the **secondar
```bash
# Stop gitlab and remove its supervision process
sudo gitlab-ctl uninstall
-
+
# Debian/Ubuntu
sudo dpkg --remove gitlab-ee
-
+
# Redhat/Centos
sudo rpm --erase gitlab-ee
```
@@ -32,9 +32,9 @@ Once GitLab has been uninstalled from the **secondary** node, the replication sl
1. On the **primary** node, start a PostgreSQL console session:
```bash
- sudo gitlab-psql
+ sudo gitlab-psql
```
-
+
NOTE: **Note:**
Using `gitlab-rails dbconsole` will not work, because managing replication slots requires superuser permissions.
@@ -43,9 +43,9 @@ Once GitLab has been uninstalled from the **secondary** node, the replication sl
```sql
SELECT * FROM pg_replication_slots;
```
-
+
1. Remove the replication slot for the **secondary** node:
```sql
SELECT pg_drop_replication_slot('<name_of_slot>');
- ```
+ ```
diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md
index c27f6c78455..166ee94eca4 100644
--- a/doc/administration/geo/replication/updating_the_geo_nodes.md
+++ b/doc/administration/geo/replication/updating_the_geo_nodes.md
@@ -14,6 +14,16 @@ all you need to do is update GitLab itself:
the tracking database is enabled.
1. [Test](#check-status-after-updating) **primary** and **secondary** nodes, and check version in each.
+## Upgrading to GitLab 12.1
+
+By default, GitLab 12.1 will attempt to automatically upgrade the embedded PostgreSQL server to 10.7 from 9.6. Please see [the omnibus documentation](https://docs.gitlab.com/omnibus/settings/database.html#upgrading-a-geo-instance) for the recommended procedure.
+
+This can be temporarily disabled by running the following before ugprading:
+
+```sh
+sudo touch /etc/gitlab/disable-postgresql-upgrade
+```
+
## Upgrading to GitLab 10.8
Before 10.8, broadcast messages would not propagate without flushing the cache on the **secondary** nodes. This has been fixed in 10.8, but requires one last cache flush on each **secondary** node:
diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md
index e81d2741082..41ef68f5b57 100644
--- a/doc/administration/high_availability/README.md
+++ b/doc/administration/high_availability/README.md
@@ -1,3 +1,7 @@
+---
+type: reference, concepts
+---
+
# Scaling and High Availability
GitLab supports several different types of clustering and high-availability.
@@ -162,14 +166,14 @@ contention due to certain workloads.
- **Status:** Work-in-progress
- **Supported Users (approximate):** 10,000
-- **Related Issues:** [gitlab-com/support/support-team-meta#1513](https://gitlab.com/gitlab-com/support/support-team-meta/issues/1513),
+- **Related Issues:** [gitlab-com/support/support-team-meta#1513](https://gitlab.com/gitlab-com/support/support-team-meta/issues/1513),
[gitlab-org/quality/team-tasks#110](https://gitlab.com/gitlab-org/quality/team-tasks/issues/110)
The Support and Quality teams are in the process of building and performance testing
an environment that will support about 10,000 users. The specifications below
-are a work-in-progress representation of the work so far. Quality will be
-certifying this environment in FY20-Q2. The specifications may be adjusted
-prior to certification based on performance testing.
+are a work-in-progress representation of the work so far. Quality will be
+certifying this environment in FY20-Q2. The specifications may be adjusted
+prior to certification based on performance testing.
- 3 PostgreSQL - 4 CPU, 8GB RAM per node
- 1 PgBouncer - 2 CPU, 4GB RAM
@@ -211,4 +215,3 @@ separately:
1. [Configure the GitLab application servers](gitlab.md)
1. [Configure the load balancers](load_balancer.md)
1. [Monitoring node (Prometheus and Grafana)](monitoring_node.md)
-
diff --git a/doc/administration/high_availability/alpha_database.md b/doc/administration/high_availability/alpha_database.md
index 7bf20be60e6..7afd739f44c 100644
--- a/doc/administration/high_availability/alpha_database.md
+++ b/doc/administration/high_availability/alpha_database.md
@@ -2,5 +2,4 @@
redirect_to: 'database.md'
---
-This documentation has been moved to the main
-[database documentation](database.md#configure_using_omnibus_for_high_availability).
+This document was moved to [another location](database.md).
diff --git a/doc/administration/high_availability/consul.md b/doc/administration/high_availability/consul.md
index 49199b659bc..b02a61b9256 100644
--- a/doc/administration/high_availability/consul.md
+++ b/doc/administration/high_availability/consul.md
@@ -1,6 +1,8 @@
-# Working with the bundled Consul service **(PREMIUM ONLY)**
+---
+type: reference
+---
-## Overview
+# Working with the bundled Consul service **(PREMIUM ONLY)**
As part of its High Availability stack, GitLab Premium includes a bundled version of [Consul](https://www.consul.io/) that can be managed through `/etc/gitlab/gitlab.rb`.
@@ -26,27 +28,27 @@ On each Consul node perform the following:
1. Edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
- ```ruby
- # Disable all components except Consul
- roles ['consul_role']
+ ```ruby
+ # Disable all components except Consul
+ roles ['consul_role']
- # START user configuration
- # Replace placeholders:
- #
- # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
- # with the addresses gathered for CONSUL_SERVER_NODES
- consul['configuration'] = {
- server: true,
- retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
- }
+ # START user configuration
+ # Replace placeholders:
+ #
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses gathered for CONSUL_SERVER_NODES
+ consul['configuration'] = {
+ server: true,
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
+ }
- # Disable auto migrations
- gitlab_rails['auto_migrate'] = false
- #
- # END user configuration
- ```
+ # Disable auto migrations
+ gitlab_rails['auto_migrate'] = false
+ #
+ # END user configuration
+ ```
- > `consul_role` was introduced with GitLab 10.3
+ > `consul_role` was introduced with GitLab 10.3
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes
to take effect.
@@ -77,6 +79,7 @@ check the [Troubleshooting section](#troubleshooting) before proceeding.
### Checking cluster membership
To see which nodes are part of the cluster, run the following on any member in the cluster
+
```
# /opt/gitlab/embedded/bin/consul members
Node Address Status Type Build Protocol DC
@@ -112,18 +115,18 @@ You will see messages like the following in `gitlab-ctl tail consul` output if y
2017-09-25_19:53:41.74356 2017/09/25 19:53:41 [ERR] agent: failed to sync remote state: No cluster leader
```
-
To fix this:
1. Pick an address on each node that all of the other nodes can reach this node through.
1. Update your `/etc/gitlab/gitlab.rb`
- ```ruby
- consul['configuration'] = {
- ...
- bind_addr: 'IP ADDRESS'
- }
- ```
+ ```ruby
+ consul['configuration'] = {
+ ...
+ bind_addr: 'IP ADDRESS'
+ }
+ ```
+
1. Run `gitlab-ctl reconfigure`
If you still see the errors, you may have to [erase the consul database and reinitialize](#recreate-from-scratch) on the affected node.
@@ -144,12 +147,13 @@ To fix this:
1. Pick an address on the node that all of the other nodes can reach this node through.
1. Update your `/etc/gitlab/gitlab.rb`
- ```ruby
- consul['configuration'] = {
- ...
- bind_addr: 'IP ADDRESS'
- }
- ```
+ ```ruby
+ consul['configuration'] = {
+ ...
+ bind_addr: 'IP ADDRESS'
+ }
+ ```
+
1. Run `gitlab-ctl reconfigure`
### Outage recovery
@@ -157,6 +161,7 @@ To fix this:
If you lost enough server agents in the cluster to break quorum, then the cluster is considered failed, and it will not function without manual intervenetion.
#### Recreate from scratch
+
By default, GitLab does not store anything in the consul cluster that cannot be recreated. To erase the consul database and reinitialize
```
@@ -168,4 +173,5 @@ By default, GitLab does not store anything in the consul cluster that cannot be
After this, the cluster should start back up, and the server agents rejoin. Shortly after that, the client agents should rejoin as well.
#### Recover a failed cluster
+
If you have taken advantage of consul to store other data, and want to restore the failed cluster, please follow the [Consul guide](https://www.consul.io/docs/guides/outage.html) to recover a failed cluster.
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
index 0db9985acd9..f7a1f425b40 100644
--- a/doc/administration/high_availability/database.md
+++ b/doc/administration/high_availability/database.md
@@ -1,5 +1,12 @@
+---
+type: reference
+---
+
# Configuring PostgreSQL for Scaling and High Availability
+In this section, you'll be guided through configuring a PostgreSQL database
+to be used with GitLab in a highly available environment.
+
## Provide your own PostgreSQL instance **(CORE ONLY)**
If you're hosting GitLab on a cloud provider, you can optionally use a
@@ -33,15 +40,15 @@ deploy the bundled PostgreSQL.
1. SSH into the PostgreSQL server.
1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- - Do not complete any other steps on the download page.
+ - Do not complete any other steps on the download page.
1. Generate a password hash for PostgreSQL. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
step as the value of `POSTGRESQL_PASSWORD_HASH`.
- ```sh
- sudo gitlab-ctl pg-password-md5 gitlab
- ```
+ ```sh
+ sudo gitlab-ctl pg-password-md5 gitlab
+ ```
1. Edit `/etc/gitlab/gitlab.rb` and add the contents below, updating placeholder
values appropriately.
@@ -51,32 +58,32 @@ deploy the bundled PostgreSQL.
addresses of the GitLab application servers that will connect to the
database. Example: `%w(123.123.123.123/32 123.123.123.234/32)`
- ```ruby
- # Disable all components except PostgreSQL
- roles ['postgres_role']
- repmgr['enable'] = false
- consul['enable'] = false
- prometheus['enable'] = false
- alertmanager['enable'] = false
- pgbouncer_exporter['enable'] = false
- redis_exporter['enable'] = false
- gitlab_monitor['enable'] = false
-
- postgresql['listen_address'] = '0.0.0.0'
- postgresql['port'] = 5432
-
- # Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
- postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
-
- # Replace XXX.XXX.XXX.XXX/YY with Network Address
- # ????
- postgresql['trust_auth_cidr_addresses'] = %w(APPLICATION_SERVER_IP_BLOCKS)
-
- # Disable automatic database migrations
- gitlab_rails['auto_migrate'] = false
- ```
+ ```ruby
+ # Disable all components except PostgreSQL
+ roles ['postgres_role']
+ repmgr['enable'] = false
+ consul['enable'] = false
+ prometheus['enable'] = false
+ alertmanager['enable'] = false
+ pgbouncer_exporter['enable'] = false
+ redis_exporter['enable'] = false
+ gitlab_monitor['enable'] = false
+
+ postgresql['listen_address'] = '0.0.0.0'
+ postgresql['port'] = 5432
+
+ # Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
+ postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
+
+ # Replace XXX.XXX.XXX.XXX/YY with Network Address
+ # ????
+ postgresql['trust_auth_cidr_addresses'] = %w(APPLICATION_SERVER_IP_BLOCKS)
+
+ # Disable automatic database migrations
+ gitlab_rails['auto_migrate'] = false
+ ```
- NOTE: **Note:** The role `postgres_role` was introduced with GitLab 10.3
+ NOTE: **Note:** The role `postgres_role` was introduced with GitLab 10.3
1. [Reconfigure GitLab] for the changes to take effect.
1. Note the PostgreSQL node's IP address or hostname, port, and
@@ -194,9 +201,9 @@ When using default setup, minimum configuration requires:
- `CONSUL_PASSWORD_HASH`. This is a hash generated out of consul username/password pair.
Can be generated with:
- ```sh
- sudo gitlab-ctl pg-password-md5 CONSUL_USERNAME
- ```
+ ```sh
+ sudo gitlab-ctl pg-password-md5 CONSUL_USERNAME
+ ```
- `CONSUL_SERVER_NODES`. The IP addresses or DNS records of the Consul server nodes.
@@ -237,9 +244,9 @@ We will need the following password information for the application's database u
- `POSTGRESQL_PASSWORD_HASH`. This is a hash generated out of the username/password pair.
Can be generated with:
- ```sh
- sudo gitlab-ctl pg-password-md5 POSTGRESQL_USERNAME
- ```
+ ```sh
+ sudo gitlab-ctl pg-password-md5 POSTGRESQL_USERNAME
+ ```
##### Pgbouncer information
@@ -250,9 +257,9 @@ When using default setup, minimum configuration requires:
- `PGBOUNCER_PASSWORD_HASH`. This is a hash generated out of pgbouncer username/password pair.
Can be generated with:
- ```sh
- sudo gitlab-ctl pg-password-md5 PGBOUNCER_USERNAME
- ```
+ ```sh
+ sudo gitlab-ctl pg-password-md5 PGBOUNCER_USERNAME
+ ```
- `PGBOUNCER_NODE`, is the IP address or a FQDN of the node running Pgbouncer.
@@ -288,7 +295,6 @@ Make sure you install the necessary dependencies from step 1,
add GitLab package repository from step 2.
When installing the GitLab package, do not supply `EXTERNAL_URL` value.
-
#### Configuring the Database nodes
1. Make sure to [configure the Consul nodes](consul.md).
@@ -296,53 +302,54 @@ When installing the GitLab package, do not supply `EXTERNAL_URL` value.
1. On the master database node, edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
- ```ruby
- # Disable all components except PostgreSQL and Repmgr and Consul
- roles ['postgres_role']
-
- # PostgreSQL configuration
- postgresql['listen_address'] = '0.0.0.0'
- postgresql['hot_standby'] = 'on'
- postgresql['wal_level'] = 'replica'
- postgresql['shared_preload_libraries'] = 'repmgr_funcs'
-
- # Disable automatic database migrations
- gitlab_rails['auto_migrate'] = false
-
- # Configure the consul agent
- consul['services'] = %w(postgresql)
-
- # START user configuration
- # Please set the real values as explained in Required Information section
- #
- # Replace PGBOUNCER_PASSWORD_HASH with a generated md5 value
- postgresql['pgbouncer_user_password'] = 'PGBOUNCER_PASSWORD_HASH'
- # Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
- postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
- # Replace X with value of number of db nodes + 1
- postgresql['max_wal_senders'] = X
-
- # Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(XXX.XXX.XXX.XXX/YY)
- repmgr['trust_auth_cidr_addresses'] = %w(127.0.0.1/32 XXX.XXX.XXX.XXX/YY)
-
- # Replace placeholders:
- #
- # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
- # with the addresses gathered for CONSUL_SERVER_NODES
- consul['configuration'] = {
- retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
- }
- #
- # END user configuration
- ```
-
- > `postgres_role` was introduced with GitLab 10.3
+ ```ruby
+ # Disable all components except PostgreSQL and Repmgr and Consul
+ roles ['postgres_role']
+
+ # PostgreSQL configuration
+ postgresql['listen_address'] = '0.0.0.0'
+ postgresql['hot_standby'] = 'on'
+ postgresql['wal_level'] = 'replica'
+ postgresql['shared_preload_libraries'] = 'repmgr_funcs'
+
+ # Disable automatic database migrations
+ gitlab_rails['auto_migrate'] = false
+
+ # Configure the consul agent
+ consul['services'] = %w(postgresql)
+
+ # START user configuration
+ # Please set the real values as explained in Required Information section
+ #
+ # Replace PGBOUNCER_PASSWORD_HASH with a generated md5 value
+ postgresql['pgbouncer_user_password'] = 'PGBOUNCER_PASSWORD_HASH'
+ # Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
+ postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
+ # Replace X with value of number of db nodes + 1
+ postgresql['max_wal_senders'] = X
+
+ # Replace XXX.XXX.XXX.XXX/YY with Network Address
+ postgresql['trust_auth_cidr_addresses'] = %w(XXX.XXX.XXX.XXX/YY)
+ repmgr['trust_auth_cidr_addresses'] = %w(127.0.0.1/32 XXX.XXX.XXX.XXX/YY)
+
+ # Replace placeholders:
+ #
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses gathered for CONSUL_SERVER_NODES
+ consul['configuration'] = {
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
+ }
+ #
+ # END user configuration
+ ```
+
+ > `postgres_role` was introduced with GitLab 10.3
1. On secondary nodes, add all the configuration specified above for primary node
to `/etc/gitlab/gitlab.rb`. In addition, append the following configuration
to inform gitlab-ctl that they are standby nodes initially and it need not
attempt to register them as primary node
+
```
# HA setting to specify if a node should attempt to be master on initialization
repmgr['master_on_initialization'] = false
@@ -367,31 +374,31 @@ Select one node as a primary node.
1. Open a database prompt:
- ```sh
- gitlab-psql -d gitlabhq_production
- ```
+ ```sh
+ gitlab-psql -d gitlabhq_production
+ ```
1. Enable the `pg_trgm` extension:
- ```sh
- CREATE EXTENSION pg_trgm;
- ```
+ ```sh
+ CREATE EXTENSION pg_trgm;
+ ```
1. Exit the database prompt by typing `\q` and Enter.
1. Verify the cluster is initialized with one node:
- ```sh
- gitlab-ctl repmgr cluster show
- ```
+ ```sh
+ gitlab-ctl repmgr cluster show
+ ```
- The output should be similar to the following:
+ The output should be similar to the following:
- ```
- Role | Name | Upstream | Connection String
- ----------+----------|----------|----------------------------------------
- * master | HOSTNAME | | host=HOSTNAME user=gitlab_repmgr dbname=gitlab_repmgr
- ```
+ ```
+ Role | Name | Upstream | Connection String
+ ----------+----------|----------|----------------------------------------
+ * master | HOSTNAME | | host=HOSTNAME user=gitlab_repmgr dbname=gitlab_repmgr
+ ```
1. Note down the hostname/ip in the connection string: `host=HOSTNAME`. We will
refer to the hostname in the next section as `MASTER_NODE_NAME`. If the value
@@ -402,43 +409,43 @@ Select one node as a primary node.
1. Set up the repmgr standby:
- ```sh
- gitlab-ctl repmgr standby setup MASTER_NODE_NAME
- ```
-
- Do note that this will remove the existing data on the node. The command
- has a wait time.
-
- The output should be similar to the following:
-
- ```console
- # gitlab-ctl repmgr standby setup MASTER_NODE_NAME
- Doing this will delete the entire contents of /var/opt/gitlab/postgresql/data
- If this is not what you want, hit Ctrl-C now to exit
- To skip waiting, rerun with the -w option
- Sleeping for 30 seconds
- Stopping the database
- Removing the data
- Cloning the data
- Starting the database
- Registering the node with the cluster
- ok: run: repmgrd: (pid 19068) 0s
- ```
+ ```sh
+ gitlab-ctl repmgr standby setup MASTER_NODE_NAME
+ ```
+
+ Do note that this will remove the existing data on the node. The command
+ has a wait time.
+
+ The output should be similar to the following:
+
+ ```console
+ # gitlab-ctl repmgr standby setup MASTER_NODE_NAME
+ Doing this will delete the entire contents of /var/opt/gitlab/postgresql/data
+ If this is not what you want, hit Ctrl-C now to exit
+ To skip waiting, rerun with the -w option
+ Sleeping for 30 seconds
+ Stopping the database
+ Removing the data
+ Cloning the data
+ Starting the database
+ Registering the node with the cluster
+ ok: run: repmgrd: (pid 19068) 0s
+ ```
1. Verify the node now appears in the cluster:
- ```sh
- gitlab-ctl repmgr cluster show
- ```
+ ```sh
+ gitlab-ctl repmgr cluster show
+ ```
- The output should be similar to the following:
+ The output should be similar to the following:
- ```
- Role | Name | Upstream | Connection String
- ----------+---------|-----------|------------------------------------------------
- * master | MASTER | | host=MASTER_NODE_NAME user=gitlab_repmgr dbname=gitlab_repmgr
- standby | STANDBY | MASTER | host=STANDBY_HOSTNAME user=gitlab_repmgr dbname=gitlab_repmgr
- ```
+ ```
+ Role | Name | Upstream | Connection String
+ ----------+---------|-----------|------------------------------------------------
+ * master | MASTER | | host=MASTER_NODE_NAME user=gitlab_repmgr dbname=gitlab_repmgr
+ standby | STANDBY | MASTER | host=STANDBY_HOSTNAME user=gitlab_repmgr dbname=gitlab_repmgr
+ ```
Repeat the above steps on all secondary nodes.
@@ -487,15 +494,15 @@ attributes set, but the following need to be set.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- # Disable PostgreSQL on the application node
- postgresql['enable'] = false
+ ```ruby
+ # Disable PostgreSQL on the application node
+ postgresql['enable'] = false
- gitlab_rails['db_host'] = 'PGBOUNCER_NODE'
- gitlab_rails['db_port'] = 6432
- gitlab_rails['db_password'] = 'POSTGRESQL_USER_PASSWORD'
- gitlab_rails['auto_migrate'] = false
- ```
+ gitlab_rails['db_host'] = 'PGBOUNCER_NODE'
+ gitlab_rails['db_port'] = 6432
+ gitlab_rails['db_password'] = 'POSTGRESQL_USER_PASSWORD'
+ gitlab_rails['auto_migrate'] = false
+ ```
1. [Reconfigure GitLab] for the changes to take effect.
@@ -655,45 +662,45 @@ After deploying the configuration follow these steps:
1. On `10.6.0.21`, our primary database
- Enable the `pg_trgm` extension
+ Enable the `pg_trgm` extension
- ```sh
- gitlab-psql -d gitlabhq_production
- ```
+ ```sh
+ gitlab-psql -d gitlabhq_production
+ ```
- ```
- CREATE EXTENSION pg_trgm;
- ```
+ ```
+ CREATE EXTENSION pg_trgm;
+ ```
1. On `10.6.0.22`, our first standby database
- Make this node a standby of the primary
+ Make this node a standby of the primary
- ```sh
- gitlab-ctl repmgr standby setup 10.6.0.21
- ```
+ ```sh
+ gitlab-ctl repmgr standby setup 10.6.0.21
+ ```
1. On `10.6.0.23`, our second standby database
- Make this node a standby of the primary
+ Make this node a standby of the primary
- ```sh
- gitlab-ctl repmgr standby setup 10.6.0.21
- ```
+ ```sh
+ gitlab-ctl repmgr standby setup 10.6.0.21
+ ```
1. On `10.6.0.31`, our application server
- Set gitlab-consul's pgbouncer password to `toomanysecrets`
+ Set gitlab-consul's pgbouncer password to `toomanysecrets`
- ```sh
- gitlab-ctl write-pgpass --host 127.0.0.1 --database pgbouncer --user pgbouncer --hostuser gitlab-consul
- ```
+ ```sh
+ gitlab-ctl write-pgpass --host 127.0.0.1 --database pgbouncer --user pgbouncer --hostuser gitlab-consul
+ ```
- Run database migrations
+ Run database migrations
- ```sh
- gitlab-rake gitlab:db:configure
- ```
+ ```sh
+ gitlab-rake gitlab:db:configure
+ ```
#### Example minimal setup
@@ -830,16 +837,16 @@ standby nodes.
1. Ensure the old master node is not still active.
1. Login to the server that should become the new master and run:
- ```sh
- gitlab-ctl repmgr standby promote
- ```
+ ```sh
+ gitlab-ctl repmgr standby promote
+ ```
1. If there are any other standby servers in the cluster, have them follow
the new master server:
- ```sh
- gitlab-ctl repmgr standby follow NEW_MASTER
- ```
+ ```sh
+ gitlab-ctl repmgr standby follow NEW_MASTER
+ ```
#### Restore procedure
@@ -849,42 +856,42 @@ after it has been restored to service.
- If you want to remove the node from the cluster, on any other node in the
cluster, run:
- ```sh
- gitlab-ctl repmgr standby unregister --node=X
- ```
+ ```sh
+ gitlab-ctl repmgr standby unregister --node=X
+ ```
- where X is the value of node in `repmgr.conf` on the old server.
+ where X is the value of node in `repmgr.conf` on the old server.
- To find this, you can use:
+ To find this, you can use:
- ```sh
- awk -F = '$1 == "node" { print $2 }' /var/opt/gitlab/postgresql/repmgr.conf
- ```
+ ```sh
+ awk -F = '$1 == "node" { print $2 }' /var/opt/gitlab/postgresql/repmgr.conf
+ ```
- It will output something like:
+ It will output something like:
- ```
- 959789412
- ```
+ ```
+ 959789412
+ ```
- Then you will use this id to unregister the node:
+ Then you will use this id to unregister the node:
- ```sh
- gitlab-ctl repmgr standby unregister --node=959789412
- ```
+ ```sh
+ gitlab-ctl repmgr standby unregister --node=959789412
+ ```
- To add the node as a standby server:
- ```sh
- gitlab-ctl repmgr standby follow NEW_MASTER
- gitlab-ctl restart repmgrd
- ```
+ ```sh
+ gitlab-ctl repmgr standby follow NEW_MASTER
+ gitlab-ctl restart repmgrd
+ ```
- CAUTION: **Warning:** When the server is brought back online, and before
- you switch it to a standby node, repmgr will report that there are two masters.
- If there are any clients that are still attempting to write to the old master,
- this will cause a split, and the old master will need to be resynced from
- scratch by performing a `gitlab-ctl repmgr standby setup NEW_MASTER`.
+ CAUTION: **Warning:** When the server is brought back online, and before
+ you switch it to a standby node, repmgr will report that there are two masters.
+ If there are any clients that are still attempting to write to the old master,
+ this will cause a split, and the old master will need to be resynced from
+ scratch by performing a `gitlab-ctl repmgr standby setup NEW_MASTER`.
#### Alternate configurations
@@ -927,13 +934,13 @@ the previous section:
1. On the current master node, create a password for the `gitlab` and
`gitlab_repmgr` user:
- ```sh
- gitlab-psql -d template1
- template1=# \password gitlab_repmgr
- Enter password: ****
- Confirm password: ****
- template1=# \password gitlab
- ```
+ ```sh
+ gitlab-psql -d template1
+ template1=# \password gitlab_repmgr
+ Enter password: ****
+ Confirm password: ****
+ template1=# \password gitlab
+ ```
1. On each database node:
@@ -947,9 +954,9 @@ the previous section:
1. Create a `.pgpass` file. Enter the `gitlab_repmgr` password twice to
when asked:
- ```sh
- gitlab-ctl write-pgpass --user gitlab_repmgr --hostuser gitlab-psql --database '*'
- ```
+ ```sh
+ gitlab-ctl write-pgpass --user gitlab_repmgr --hostuser gitlab-psql --database '*'
+ ```
1. On each pgbouncer node, edit `/etc/gitlab/gitlab.rb`:
1. Ensure `gitlab_rails['db_password']` is set to the plaintext password for
@@ -977,7 +984,7 @@ If you enable Monitoring, it must be enabled on **all** database servers.
## Troubleshooting
-### Consul and PostgreSQL changes not taking effect.
+### Consul and PostgreSQL changes not taking effect
Due to the potential impacts, `gitlab-ctl reconfigure` only reloads Consul and PostgreSQL, it will not restart the services. However, not all changes can be activated by reloading.
diff --git a/doc/administration/high_availability/gitaly.md b/doc/administration/high_availability/gitaly.md
index b7eaa4ce105..739d1ae35fb 100644
--- a/doc/administration/high_availability/gitaly.md
+++ b/doc/administration/high_availability/gitaly.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Configuring Gitaly for Scaled and High Availability
Gitaly does not yet support full high availability. However, Gitaly is quite
@@ -46,3 +50,15 @@ Continue configuration of other components by going back to:
```
1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
index 9b1b7142e83..8818a9606de 100644
--- a/doc/administration/high_availability/gitlab.md
+++ b/doc/administration/high_availability/gitlab.md
@@ -1,4 +1,8 @@
-# Configuring GitLab Scaling and High Availability
+---
+type: reference
+---
+
+# Configuring GitLab for Scaling and High Availability
> **Note:** There is some additional configuration near the bottom for
additional GitLab application servers. It's important to read and understand
@@ -7,33 +11,33 @@
1. If necessary, install the NFS client utility packages using the following
commands:
- ```
- # Ubuntu/Debian
- apt-get install nfs-common
+ ```
+ # Ubuntu/Debian
+ apt-get install nfs-common
- # CentOS/Red Hat
- yum install nfs-utils nfs-utils-lib
- ```
+ # CentOS/Red Hat
+ yum install nfs-utils nfs-utils-lib
+ ```
1. Specify the necessary NFS shares. Mounts are specified in
`/etc/fstab`. The exact contents of `/etc/fstab` will depend on how you chose
to configure your NFS server. See [NFS documentation](nfs.md) for the various
options. Here is an example snippet to add to `/etc/fstab`:
- ```
- 10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
- 10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
- 10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
- 10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
- 10.1.0.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
- ```
+ ```
+ 10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ ```
1. Create the shared directories. These may be different depending on your NFS
mount locations.
- ```
- mkdir -p /var/opt/gitlab/.ssh /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/git-data
- ```
+ ```
+ mkdir -p /var/opt/gitlab/.ssh /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/git-data
+ ```
1. Download/install GitLab Omnibus using **steps 1 and 2** from
[GitLab downloads](https://about.gitlab.com/downloads). Do not complete other
@@ -46,52 +50,52 @@
added NFS mounts in the default data locations. Additionally the UID and GIDs
given are just examples and you should configure with your preferred values.
- ```ruby
- external_url 'https://gitlab.example.com'
-
- # Prevent GitLab from starting if NFS data mounts are not available
- high_availability['mountpoint'] = '/var/opt/gitlab/git-data'
-
- # Disable components that will not be on the GitLab application server
- roles ['application_role']
- nginx['enable'] = true
-
- # PostgreSQL connection details
- gitlab_rails['db_adapter'] = 'postgresql'
- gitlab_rails['db_encoding'] = 'unicode'
- gitlab_rails['db_host'] = '10.1.0.5' # IP/hostname of database server
- gitlab_rails['db_password'] = 'DB password'
-
- # Redis connection details
- gitlab_rails['redis_port'] = '6379'
- gitlab_rails['redis_host'] = '10.1.0.6' # IP/hostname of Redis server
- gitlab_rails['redis_password'] = 'Redis Password'
-
- # Ensure UIDs and GIDs match between servers for permissions via NFS
- user['uid'] = 9000
- user['gid'] = 9000
- web_server['uid'] = 9001
- web_server['gid'] = 9001
- registry['uid'] = 9002
- registry['gid'] = 9002
- ```
+ ```ruby
+ external_url 'https://gitlab.example.com'
+
+ # Prevent GitLab from starting if NFS data mounts are not available
+ high_availability['mountpoint'] = '/var/opt/gitlab/git-data'
+
+ # Disable components that will not be on the GitLab application server
+ roles ['application_role']
+ nginx['enable'] = true
+
+ # PostgreSQL connection details
+ gitlab_rails['db_adapter'] = 'postgresql'
+ gitlab_rails['db_encoding'] = 'unicode'
+ gitlab_rails['db_host'] = '10.1.0.5' # IP/hostname of database server
+ gitlab_rails['db_password'] = 'DB password'
+
+ # Redis connection details
+ gitlab_rails['redis_port'] = '6379'
+ gitlab_rails['redis_host'] = '10.1.0.6' # IP/hostname of Redis server
+ gitlab_rails['redis_password'] = 'Redis Password'
+
+ # Ensure UIDs and GIDs match between servers for permissions via NFS
+ user['uid'] = 9000
+ user['gid'] = 9000
+ web_server['uid'] = 9001
+ web_server['gid'] = 9001
+ registry['uid'] = 9002
+ registry['gid'] = 9002
+ ```
1. [Enable monitoring](#enable-monitoring)
- > **Note:** To maintain uniformity of links across HA clusters, the `external_url`
- on the first application server as well as the additional application
- servers should point to the external url that users will use to access GitLab.
- In a typical HA setup, this will be the url of the load balancer which will
- route traffic to all GitLab application servers in the HA cluster.
- >
- > **Note:** When you specify `https` in the `external_url`, as in the example
- above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
- certificates are not present, Nginx will fail to start. See
- [Nginx documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
- for more information.
- >
- > **Note:** It is best to set the `uid` and `gid`s prior to the initial reconfigure
- of GitLab. Omnibus will not recursively `chown` directories if set after the initial reconfigure.
+ > **Note:** To maintain uniformity of links across HA clusters, the `external_url`
+ on the first application server as well as the additional application
+ servers should point to the external url that users will use to access GitLab.
+ In a typical HA setup, this will be the url of the load balancer which will
+ route traffic to all GitLab application servers in the HA cluster.
+ >
+ > **Note:** When you specify `https` in the `external_url`, as in the example
+ above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
+ certificates are not present, Nginx will fail to start. See
+ [Nginx documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
+ for more information.
+ >
+ > **Note:** It is best to set the `uid` and `gid`s prior to the initial reconfigure
+ of GitLab. Omnibus will not recursively `chown` directories if set after the initial reconfigure.
## First GitLab application server
@@ -114,12 +118,12 @@ need some extra configuration.
secondary servers **prior to** running the first `reconfigure` in the steps
above.
- ```ruby
- gitlab_shell['secret_token'] = 'fbfb19c355066a9afb030992231c4a363357f77345edd0f2e772359e5be59b02538e1fa6cae8f93f7d23355341cea2b93600dab6d6c3edcdced558fc6d739860'
- gitlab_rails['otp_key_base'] = 'b719fe119132c7810908bba18315259ed12888d4f5ee5430c42a776d840a396799b0a5ef0a801348c8a357f07aa72bbd58e25a84b8f247a25c72f539c7a6c5fa'
- gitlab_rails['secret_key_base'] = '6e657410d57c71b4fc3ed0d694e7842b1895a8b401d812c17fe61caf95b48a6d703cb53c112bc01ebd197a85da81b18e29682040e99b4f26594772a4a2c98c6d'
- gitlab_rails['db_key_base'] = 'bf2e47b68d6cafaef1d767e628b619365becf27571e10f196f98dc85e7771042b9203199d39aff91fcb6837c8ed83f2a912b278da50999bb11a2fbc0fba52964'
- ```
+ ```ruby
+ gitlab_shell['secret_token'] = 'fbfb19c355066a9afb030992231c4a363357f77345edd0f2e772359e5be59b02538e1fa6cae8f93f7d23355341cea2b93600dab6d6c3edcdced558fc6d739860'
+ gitlab_rails['otp_key_base'] = 'b719fe119132c7810908bba18315259ed12888d4f5ee5430c42a776d840a396799b0a5ef0a801348c8a357f07aa72bbd58e25a84b8f247a25c72f539c7a6c5fa'
+ gitlab_rails['secret_key_base'] = '6e657410d57c71b4fc3ed0d694e7842b1895a8b401d812c17fe61caf95b48a6d703cb53c112bc01ebd197a85da81b18e29682040e99b4f26594772a4a2c98c6d'
+ gitlab_rails['db_key_base'] = 'bf2e47b68d6cafaef1d767e628b619365becf27571e10f196f98dc85e7771042b9203199d39aff91fcb6837c8ed83f2a912b278da50999bb11a2fbc0fba52964'
+ ```
1. Run `touch /etc/gitlab/skip-auto-reconfigure` to prevent database migrations
from running on upgrade. Only the primary GitLab application server should
diff --git a/doc/administration/high_availability/load_balancer.md b/doc/administration/high_availability/load_balancer.md
index 28b226cacd5..9e9f604317a 100644
--- a/doc/administration/high_availability/load_balancer.md
+++ b/doc/administration/high_availability/load_balancer.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Load Balancer for GitLab HA
In an active/active GitLab configuration, you will need a load balancer to route
@@ -114,3 +118,15 @@ Read more on high-availability configuration:
if SSL was terminated at the load balancer.
[gitlab-pages]: ../pages/index.md
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/high_availability/monitoring_node.md b/doc/administration/high_availability/monitoring_node.md
index ce58092b922..b91a994d01e 100644
--- a/doc/administration/high_availability/monitoring_node.md
+++ b/doc/administration/high_availability/monitoring_node.md
@@ -1,7 +1,13 @@
+---
+type: reference
+---
+
# Configuring a Monitoring node for Scaling and High Availability
> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3786) in GitLab 12.0.
+You can configure a Prometheus node to monitor GitLab.
+
## Standalone Monitoring node using GitLab Omnibus
The GitLab Omnibus package can be used to configure a standalone Monitoring node running [Prometheus](../monitoring/prometheus/index.md) and [Grafana](../monitoring/performance/grafana_configuration.md).
@@ -20,44 +26,44 @@ Omnibus:
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
- ```ruby
- external_url 'http://gitlab.example.com'
-
- # Enable Prometheus
- prometheus['enable'] = true
- prometheus['listen_address'] = '0.0.0.0:9090'
- prometheus['monitor_kubernetes'] = false
-
- # Enable Grafana
- grafana['enable'] = true
- grafana['admin_password'] = 'toomanysecrets'
-
- # Enable service discovery for Prometheus
- consul['enable'] = true
- consul['monitoring_service_discovery'] = true
-
- # Replace placeholders
- # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
- # with the addresses of the Consul server nodes
- consul['configuration'] = {
- retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
- }
-
- # Disable all other services
- gitlab_rails['auto_migrate'] = false
- alertmanager['enable'] = false
- gitaly['enable'] = false
- gitlab_monitor['enable'] = false
- gitlab_workhorse['enable'] = false
- nginx['enable'] = true
- postgres_exporter['enable'] = false
- postgresql['enable'] = false
- redis['enable'] = false
- redis_exporter['enable'] = false
- sidekiq['enable'] = false
- unicorn['enable'] = false
- node_exporter['enable'] = false
- ```
+ ```ruby
+ external_url 'http://gitlab.example.com'
+
+ # Enable Prometheus
+ prometheus['enable'] = true
+ prometheus['listen_address'] = '0.0.0.0:9090'
+ prometheus['monitor_kubernetes'] = false
+
+ # Enable Grafana
+ grafana['enable'] = true
+ grafana['admin_password'] = 'toomanysecrets'
+
+ # Enable service discovery for Prometheus
+ consul['enable'] = true
+ consul['monitoring_service_discovery'] = true
+
+ # Replace placeholders
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses of the Consul server nodes
+ consul['configuration'] = {
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
+ }
+
+ # Disable all other services
+ gitlab_rails['auto_migrate'] = false
+ alertmanager['enable'] = false
+ gitaly['enable'] = false
+ gitlab_monitor['enable'] = false
+ gitlab_workhorse['enable'] = false
+ nginx['enable'] = true
+ postgres_exporter['enable'] = false
+ postgresql['enable'] = false
+ redis['enable'] = false
+ redis_exporter['enable'] = false
+ sidekiq['enable'] = false
+ unicorn['enable'] = false
+ node_exporter['enable'] = false
+ ```
1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
@@ -67,3 +73,15 @@ Once monitoring using Service Discovery is enabled with `consul['monitoring_serv
ensure that `prometheus['scrape_configs']` is not set in `/etc/gitlab/gitlab.rb`. Setting both
`consul['monitoring_service_discovery'] = true` and `prometheus['scrape_configs']` in `/etc/gitlab/gitlab.rb`
will result in errors.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md
index 561ba214686..294f0e969d5 100644
--- a/doc/administration/high_availability/nfs.md
+++ b/doc/administration/high_availability/nfs.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# NFS
You can view information and options set for each of the mounted NFS file
@@ -42,34 +46,20 @@ maintaining ID mapping without LDAP, in most cases you should enable numeric UID
and GIDs (which is off by default in some cases) for simplified permission
management between systems:
- - [NetApp instructions](https://library.netapp.com/ecmdocs/ECMP1401220/html/GUID-24367A9F-E17B-4725-ADC1-02D86F56F78E.html)
- - For non-NetApp devices, disable NFSv4 `idmapping` by performing opposite of [enable NFSv4 idmapper](https://wiki.archlinux.org/index.php/NFS#Enabling_NFSv4_idmapping)
+- [NetApp instructions](https://library.netapp.com/ecmdocs/ECMP1401220/html/GUID-24367A9F-E17B-4725-ADC1-02D86F56F78E.html)
+- For non-NetApp devices, disable NFSv4 `idmapping` by performing opposite of [enable NFSv4 idmapper](https://wiki.archlinux.org/index.php/NFS#Enabling_NFSv4_idmapping)
### Improving NFS performance with GitLab
-NOTE: **Note:** This is only available starting in certain versions of GitLab: 11.5.11,
-11.6.11, 11.7.12, 11.8.8, 11.9.0 and up (e.g. 11.10, 11.11, etc.)
+NOTE: **Note:** From GitLab 12.1, it will automatically be detected if Rugged can and should be used per storage.
-If you are using NFS to share Git data, we recommend that you enable a
-number of feature flags that will allow GitLab application processes to
-access Git data directly instead of going through the [Gitaly
-service](../gitaly/index.md). Depending on your workload and disk
-performance, these flags may help improve performance. See [the
-issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/57317) for more
-details.
-
-To do this, run the Rake task:
+If you previously enabled Rugged using the feature flag, you will need to unset the feature flag by using:
```sh
-sudo gitlab-rake gitlab:features:enable_rugged
+sudo gitlab-rake gitlab:features:unset_rugged
```
-If you need to undo this setting for some reason such as switching to [Gitaly without NFS](gitaly.md)
-(recommended), run:
-
-```sh
-sudo gitlab-rake gitlab:features:disable_rugged
-```
+If the Rugged feature flag is explicitly set to either true or false, GitLab will use the value explicitly set.
### Known issues
@@ -87,10 +77,10 @@ on an Linux NFS server, do the following:
1. On the NFS server, run:
- ```sh
- echo 0 > /proc/sys/fs/leases-enable
- sysctl -w fs.leases-enable=0
- ```
+ ```sh
+ echo 0 > /proc/sys/fs/leases-enable
+ sysctl -w fs.leases-enable=0
+ ```
1. Restart the NFS server process. For example, on CentOS run `service nfs restart`.
@@ -236,3 +226,15 @@ Read more on high-availability configuration:
1. [Configure the load balancers](load_balancer.md)
[udp-log-shipping]: https://docs.gitlab.com/omnibus/settings/logs.html#udp-log-shipping-gitlab-enterprise-edition-only "UDP log shipping"
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/high_availability/nfs_host_client_setup.md b/doc/administration/high_availability/nfs_host_client_setup.md
index a8d69b9ab0a..9b0e085fe25 100644
--- a/doc/administration/high_availability/nfs_host_client_setup.md
+++ b/doc/administration/high_availability/nfs_host_client_setup.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Configuring NFS for GitLab HA
Setting up NFS for a GitLab HA setup allows all applications nodes in a cluster
@@ -133,3 +137,15 @@ client with the command below.
```sh
sudo ufw allow from <client-ip-address> to any port nfs
```
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/administration/high_availability/pgbouncer.md b/doc/administration/high_availability/pgbouncer.md
index 2788b087628..0b945bc6244 100644
--- a/doc/administration/high_availability/pgbouncer.md
+++ b/doc/administration/high_availability/pgbouncer.md
@@ -1,6 +1,8 @@
-# Working with the bundle Pgbouncer service
+---
+type: reference
+---
-## Overview
+# Working with the bundle Pgbouncer service
As part of its High Availability stack, GitLab Premium includes a bundled version of [Pgbouncer](https://pgbouncer.github.io/) that can be managed through `/etc/gitlab/gitlab.rb`.
@@ -105,39 +107,39 @@ It is recommended to run pgbouncer alongside the `gitlab-rails` service, or on i
1. On your database node, ensure the following is set in your `/etc/gitlab/gitlab.rb`
- ```ruby
- postgresql['pgbouncer_user_password'] = 'PGBOUNCER_USER_PASSWORD_HASH'
- postgresql['sql_user_password'] = 'SQL_USER_PASSWORD_HASH'
- postgresql['listen_address'] = 'XX.XX.XX.Y' # Where XX.XX.XX.Y is the ip address on the node postgresql should listen on
- postgresql['md5_auth_cidr_addresses'] = %w(AA.AA.AA.B/32) # Where AA.AA.AA.B is the IP address of the pgbouncer node
- ```
+ ```ruby
+ postgresql['pgbouncer_user_password'] = 'PGBOUNCER_USER_PASSWORD_HASH'
+ postgresql['sql_user_password'] = 'SQL_USER_PASSWORD_HASH'
+ postgresql['listen_address'] = 'XX.XX.XX.Y' # Where XX.XX.XX.Y is the ip address on the node postgresql should listen on
+ postgresql['md5_auth_cidr_addresses'] = %w(AA.AA.AA.B/32) # Where AA.AA.AA.B is the IP address of the pgbouncer node
+ ```
1. Run `gitlab-ctl reconfigure`
- **Note:** If the database was already running, it will need to be restarted after reconfigure by running `gitlab-ctl restart postgresql`.
+ **Note:** If the database was already running, it will need to be restarted after reconfigure by running `gitlab-ctl restart postgresql`.
1. On the node you are running pgbouncer on, make sure the following is set in `/etc/gitlab/gitlab.rb`
- ```ruby
- pgbouncer['enable'] = true
- pgbouncer['databases'] = {
- gitlabhq_production: {
- host: 'DATABASE_HOST',
- user: 'pgbouncer',
- password: 'PGBOUNCER_USER_PASSWORD_HASH'
- }
- }
- ```
+ ```ruby
+ pgbouncer['enable'] = true
+ pgbouncer['databases'] = {
+ gitlabhq_production: {
+ host: 'DATABASE_HOST',
+ user: 'pgbouncer',
+ password: 'PGBOUNCER_USER_PASSWORD_HASH'
+ }
+ }
+ ```
1. Run `gitlab-ctl reconfigure`
1. On the node running unicorn, make sure the following is set in `/etc/gitlab/gitlab.rb`
- ```ruby
- gitlab_rails['db_host'] = 'PGBOUNCER_HOST'
- gitlab_rails['db_port'] = '6432'
- gitlab_rails['db_password'] = 'SQL_USER_PASSWORD'
- ```
+ ```ruby
+ gitlab_rails['db_host'] = 'PGBOUNCER_HOST'
+ gitlab_rails['db_port'] = '6432'
+ gitlab_rails['db_password'] = 'SQL_USER_PASSWORD'
+ ```
1. Run `gitlab-ctl reconfigure`
@@ -147,28 +149,28 @@ It is recommended to run pgbouncer alongside the `gitlab-rails` service, or on i
> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3786) in GitLab 12.0.
- If you enable Monitoring, it must be enabled on **all** pgbouncer servers.
+If you enable Monitoring, it must be enabled on **all** pgbouncer servers.
- 1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
+1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
- ```ruby
- # Enable service discovery for Prometheus
- consul['enable'] = true
- consul['monitoring_service_discovery'] = true
+ ```ruby
+ # Enable service discovery for Prometheus
+ consul['enable'] = true
+ consul['monitoring_service_discovery'] = true
- # Replace placeholders
- # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
- # with the addresses of the Consul server nodes
- consul['configuration'] = {
- retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
- }
+ # Replace placeholders
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses of the Consul server nodes
+ consul['configuration'] = {
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
+ }
- # Set the network addresses that the exporters will listen on
- node_exporter['listen_address'] = '0.0.0.0:9100'
- pgbouncer_exporter['listen_address'] = '0.0.0.0:9188'
- ```
+ # Set the network addresses that the exporters will listen on
+ node_exporter['listen_address'] = '0.0.0.0:9100'
+ pgbouncer_exporter['listen_address'] = '0.0.0.0:9188'
+ ```
- 1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
### Interacting with pgbouncer
@@ -190,6 +192,7 @@ pgbouncer=#
The password you will be prompted for is the PGBOUNCER_USER_PASSWORD
To get some basic information about the instance, run
+
```shell
pgbouncer=# show databases; show clients; show servers;
name | host | port | database | force_user | pool_size | reserve_pool | pool_mode | max_connections | current_connections
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index 27310c59755..1b79dde9476 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Configuring Redis for Scaling and High Availability
## Provide your own Redis instance **(CORE ONLY)**
@@ -47,28 +51,28 @@ Omnibus:
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
- ```ruby
- ## Enable Redis
- redis['enable'] = true
-
- ## Disable all other services
- sidekiq['enable'] = false
- gitlab_workhorse['enable'] = false
- unicorn['enable'] = false
- postgresql['enable'] = false
- nginx['enable'] = false
- prometheus['enable'] = false
- alertmanager['enable'] = false
- pgbouncer_exporter['enable'] = false
- gitlab_monitor['enable'] = false
- gitaly['enable'] = false
-
- redis['bind'] = '0.0.0.0'
- redis['port'] = '6379'
- redis['password'] = 'SECRET_PASSWORD_HERE'
-
- gitlab_rails['auto_migrate'] = false
- ```
+ ```ruby
+ ## Enable Redis
+ redis['enable'] = true
+
+ ## Disable all other services
+ sidekiq['enable'] = false
+ gitlab_workhorse['enable'] = false
+ unicorn['enable'] = false
+ postgresql['enable'] = false
+ nginx['enable'] = false
+ prometheus['enable'] = false
+ alertmanager['enable'] = false
+ pgbouncer_exporter['enable'] = false
+ gitlab_monitor['enable'] = false
+ gitaly['enable'] = false
+
+ redis['bind'] = '0.0.0.0'
+ redis['port'] = '6379'
+ redis['password'] = 'SECRET_PASSWORD_HERE'
+
+ gitlab_rails['auto_migrate'] = false
+ ```
1. [Reconfigure Omnibus GitLab][reconfigure] for the changes to take effect.
1. Note the Redis node's IP address or hostname, port, and
@@ -359,37 +363,37 @@ The prerequisites for a HA Redis setup are the following:
1. SSH into the **master** Redis server.
1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
+ - Make sure you select the correct Omnibus package, with the same version
+ and type (Community, Enterprise editions) of your current install.
+ - Do not complete any other steps on the download page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
- ```ruby
- # Specify server role as 'redis_master_role'
- roles ['redis_master_role']
+ ```ruby
+ # Specify server role as 'redis_master_role'
+ roles ['redis_master_role']
- # IP address pointing to a local IP that the other machines can reach to.
- # You can also set bind to '0.0.0.0' which listen in all interfaces.
- # If you really need to bind to an external accessible IP, make
- # sure you add extra firewall rules to prevent unauthorized access.
- redis['bind'] = '10.0.0.1'
+ # IP address pointing to a local IP that the other machines can reach to.
+ # You can also set bind to '0.0.0.0' which listen in all interfaces.
+ # If you really need to bind to an external accessible IP, make
+ # sure you add extra firewall rules to prevent unauthorized access.
+ redis['bind'] = '10.0.0.1'
- # Define a port so Redis can listen for TCP requests which will allow other
- # machines to connect to it.
- redis['port'] = 6379
+ # Define a port so Redis can listen for TCP requests which will allow other
+ # machines to connect to it.
+ redis['port'] = 6379
- # Set up password authentication for Redis (use the same password in all nodes).
- redis['password'] = 'redis-password-goes-here'
- ```
+ # Set up password authentication for Redis (use the same password in all nodes).
+ redis['password'] = 'redis-password-goes-here'
+ ```
1. Only the primary GitLab application server should handle migrations. To
prevent database migrations from running on upgrade, add the following
configuration to your `/etc/gitlab/gitlab.rb` file:
- ```
- gitlab_rails['auto_migrate'] = false
- ```
+ ```
+ gitlab_rails['auto_migrate'] = false
+ ```
1. [Reconfigure Omnibus GitLab][reconfigure] for the changes to take effect.
@@ -402,42 +406,42 @@ The prerequisites for a HA Redis setup are the following:
1. SSH into the **slave** Redis server.
1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
+ - Make sure you select the correct Omnibus package, with the same version
+ and type (Community, Enterprise editions) of your current install.
+ - Do not complete any other steps on the download page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
- ```ruby
- # Specify server role as 'redis_slave_role'
- roles ['redis_slave_role']
+ ```ruby
+ # Specify server role as 'redis_slave_role'
+ roles ['redis_slave_role']
- # IP address pointing to a local IP that the other machines can reach to.
- # You can also set bind to '0.0.0.0' which listen in all interfaces.
- # If you really need to bind to an external accessible IP, make
- # sure you add extra firewall rules to prevent unauthorized access.
- redis['bind'] = '10.0.0.2'
+ # IP address pointing to a local IP that the other machines can reach to.
+ # You can also set bind to '0.0.0.0' which listen in all interfaces.
+ # If you really need to bind to an external accessible IP, make
+ # sure you add extra firewall rules to prevent unauthorized access.
+ redis['bind'] = '10.0.0.2'
- # Define a port so Redis can listen for TCP requests which will allow other
- # machines to connect to it.
- redis['port'] = 6379
+ # Define a port so Redis can listen for TCP requests which will allow other
+ # machines to connect to it.
+ redis['port'] = 6379
- # The same password for Redis authentication you set up for the master node.
- redis['password'] = 'redis-password-goes-here'
+ # The same password for Redis authentication you set up for the master node.
+ redis['password'] = 'redis-password-goes-here'
- # The IP of the master Redis node.
- redis['master_ip'] = '10.0.0.1'
+ # The IP of the master Redis node.
+ redis['master_ip'] = '10.0.0.1'
- # Port of master Redis server, uncomment to change to non default. Defaults
- # to `6379`.
- #redis['master_port'] = 6379
- ```
+ # Port of master Redis server, uncomment to change to non default. Defaults
+ # to `6379`.
+ #redis['master_port'] = 6379
+ ```
1. To prevent reconfigure from running automatically on upgrade, run:
- ```
- sudo touch /etc/gitlab/skip-auto-reconfigure
- ```
+ ```
+ sudo touch /etc/gitlab/skip-auto-reconfigure
+ ```
1. [Reconfigure Omnibus GitLab][reconfigure] for the changes to take effect.
1. Go through the steps again for all the other slave nodes.
@@ -487,89 +491,89 @@ multiple machines with the Sentinel daemon.
1. **You can omit this step if the Sentinels will be hosted in the same node as
the other Redis instances.**
- [Download/install](https://about.gitlab.com/downloads-ee) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+ [Download/install](https://about.gitlab.com/downloads-ee) the
+ Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
+ GitLab downloads page.
+ - Make sure you select the correct Omnibus package, with the same version
+ the GitLab application is running.
+ - Do not complete any other steps on the download page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents (if you are installing the
Sentinels in the same node as the other Redis instances, some values might
be duplicate below):
- ```ruby
- roles ['redis_sentinel_role']
-
- # Must be the same in every sentinel node
- redis['master_name'] = 'gitlab-redis'
-
- # The same password for Redis authentication you set up for the master node.
- redis['master_password'] = 'redis-password-goes-here'
-
- # The IP of the master Redis node.
- redis['master_ip'] = '10.0.0.1'
-
- # Define a port so Redis can listen for TCP requests which will allow other
- # machines to connect to it.
- redis['port'] = 6379
-
- # Port of master Redis server, uncomment to change to non default. Defaults
- # to `6379`.
- #redis['master_port'] = 6379
-
- ## Configure Sentinel
- sentinel['bind'] = '10.0.0.1'
-
- # Port that Sentinel listens on, uncomment to change to non default. Defaults
- # to `26379`.
- # sentinel['port'] = 26379
-
- ## Quorum must reflect the amount of voting sentinels it take to start a failover.
- ## Value must NOT be greater then the amount of sentinels.
- ##
- ## The quorum can be used to tune Sentinel in two ways:
- ## 1. If a the quorum is set to a value smaller than the majority of Sentinels
- ## we deploy, we are basically making Sentinel more sensible to master failures,
- ## triggering a failover as soon as even just a minority of Sentinels is no longer
- ## able to talk with the master.
- ## 1. If a quorum is set to a value greater than the majority of Sentinels, we are
- ## making Sentinel able to failover only when there are a very large number (larger
- ## than majority) of well connected Sentinels which agree about the master being down.s
- sentinel['quorum'] = 2
-
- ## Consider unresponsive server down after x amount of ms.
- # sentinel['down_after_milliseconds'] = 10000
-
- ## Specifies the failover timeout in milliseconds. It is used in many ways:
- ##
- ## - The time needed to re-start a failover after a previous failover was
- ## already tried against the same master by a given Sentinel, is two
- ## times the failover timeout.
- ##
- ## - The time needed for a slave replicating to a wrong master according
- ## to a Sentinel current configuration, to be forced to replicate
- ## with the right master, is exactly the failover timeout (counting since
- ## the moment a Sentinel detected the misconfiguration).
- ##
- ## - The time needed to cancel a failover that is already in progress but
- ## did not produced any configuration change (SLAVEOF NO ONE yet not
- ## acknowledged by the promoted slave).
- ##
- ## - The maximum time a failover in progress waits for all the slaves to be
- ## reconfigured as slaves of the new master. However even after this time
- ## the slaves will be reconfigured by the Sentinels anyway, but not with
- ## the exact parallel-syncs progression as specified.
- # sentinel['failover_timeout'] = 60000
- ```
+ ```ruby
+ roles ['redis_sentinel_role']
+
+ # Must be the same in every sentinel node
+ redis['master_name'] = 'gitlab-redis'
+
+ # The same password for Redis authentication you set up for the master node.
+ redis['master_password'] = 'redis-password-goes-here'
+
+ # The IP of the master Redis node.
+ redis['master_ip'] = '10.0.0.1'
+
+ # Define a port so Redis can listen for TCP requests which will allow other
+ # machines to connect to it.
+ redis['port'] = 6379
+
+ # Port of master Redis server, uncomment to change to non default. Defaults
+ # to `6379`.
+ #redis['master_port'] = 6379
+
+ ## Configure Sentinel
+ sentinel['bind'] = '10.0.0.1'
+
+ # Port that Sentinel listens on, uncomment to change to non default. Defaults
+ # to `26379`.
+ # sentinel['port'] = 26379
+
+ ## Quorum must reflect the amount of voting sentinels it take to start a failover.
+ ## Value must NOT be greater then the amount of sentinels.
+ ##
+ ## The quorum can be used to tune Sentinel in two ways:
+ ## 1. If a the quorum is set to a value smaller than the majority of Sentinels
+ ## we deploy, we are basically making Sentinel more sensible to master failures,
+ ## triggering a failover as soon as even just a minority of Sentinels is no longer
+ ## able to talk with the master.
+ ## 1. If a quorum is set to a value greater than the majority of Sentinels, we are
+ ## making Sentinel able to failover only when there are a very large number (larger
+ ## than majority) of well connected Sentinels which agree about the master being down.s
+ sentinel['quorum'] = 2
+
+ ## Consider unresponsive server down after x amount of ms.
+ # sentinel['down_after_milliseconds'] = 10000
+
+ ## Specifies the failover timeout in milliseconds. It is used in many ways:
+ ##
+ ## - The time needed to re-start a failover after a previous failover was
+ ## already tried against the same master by a given Sentinel, is two
+ ## times the failover timeout.
+ ##
+ ## - The time needed for a slave replicating to a wrong master according
+ ## to a Sentinel current configuration, to be forced to replicate
+ ## with the right master, is exactly the failover timeout (counting since
+ ## the moment a Sentinel detected the misconfiguration).
+ ##
+ ## - The time needed to cancel a failover that is already in progress but
+ ## did not produced any configuration change (SLAVEOF NO ONE yet not
+ ## acknowledged by the promoted slave).
+ ##
+ ## - The maximum time a failover in progress waits for all the slaves to be
+ ## reconfigured as slaves of the new master. However even after this time
+ ## the slaves will be reconfigured by the Sentinels anyway, but not with
+ ## the exact parallel-syncs progression as specified.
+ # sentinel['failover_timeout'] = 60000
+ ```
1. To prevent database migrations from running on upgrade, run:
- ```
- sudo touch /etc/gitlab/skip-auto-reconfigure
- ```
+ ```
+ sudo touch /etc/gitlab/skip-auto-reconfigure
+ ```
- Only the primary GitLab application server should handle migrations.
+ Only the primary GitLab application server should handle migrations.
1. [Reconfigure Omnibus GitLab][reconfigure] for the changes to take effect.
1. Go through the steps again for all the other Sentinel nodes.
@@ -593,20 +597,20 @@ which ideally should not have Redis or Sentinels on it for a HA setup.
1. SSH into the server where the GitLab application is installed.
1. Edit `/etc/gitlab/gitlab.rb` and add/change the following lines:
- ```
- ## Must be the same in every sentinel node
- redis['master_name'] = 'gitlab-redis'
-
- ## The same password for Redis authentication you set up for the master node.
- redis['master_password'] = 'redis-password-goes-here'
-
- ## A list of sentinels with `host` and `port`
- gitlab_rails['redis_sentinels'] = [
- {'host' => '10.0.0.1', 'port' => 26379},
- {'host' => '10.0.0.2', 'port' => 26379},
- {'host' => '10.0.0.3', 'port' => 26379}
- ]
- ```
+ ```ruby
+ ## Must be the same in every sentinel node
+ redis['master_name'] = 'gitlab-redis'
+
+ ## The same password for Redis authentication you set up for the master node.
+ redis['master_password'] = 'redis-password-goes-here'
+
+ ## A list of sentinels with `host` and `port`
+ gitlab_rails['redis_sentinels'] = [
+ {'host' => '10.0.0.1', 'port' => 26379},
+ {'host' => '10.0.0.2', 'port' => 26379},
+ {'host' => '10.0.0.3', 'port' => 26379}
+ ]
+ ```
1. [Reconfigure Omnibus GitLab][reconfigure] for the changes to take effect.
@@ -791,31 +795,34 @@ cache, queues, and shared_state. To make this work with Sentinel:
1. Set the appropriate variable in `/etc/gitlab/gitlab.rb` for each instance you are using:
- ```ruby
- gitlab_rails['redis_cache_instance'] = REDIS_CACHE_URL
- gitlab_rails['redis_queues_instance'] = REDIS_QUEUES_URL
- gitlab_rails['redis_shared_state_instance'] = REDIS_SHARED_STATE_URL
- ```
+ ```ruby
+ gitlab_rails['redis_cache_instance'] = REDIS_CACHE_URL
+ gitlab_rails['redis_queues_instance'] = REDIS_QUEUES_URL
+ gitlab_rails['redis_shared_state_instance'] = REDIS_SHARED_STATE_URL
+ ```
+
**Note**: Redis URLs should be in the format: `redis://:PASSWORD@SENTINEL_MASTER_NAME`
- 1. PASSWORD is the plaintext password for the Redis instance
- 1. SENTINEL_MASTER_NAME is the Sentinel master name (e.g. `gitlab-redis-cache`)
+ 1. PASSWORD is the plaintext password for the Redis instance
+ 1. SENTINEL_MASTER_NAME is the Sentinel master name (e.g. `gitlab-redis-cache`)
+
1. Include an array of hashes with host/port combinations, such as the following:
- ```ruby
- gitlab_rails['redis_cache_sentinels'] = [
- { host: REDIS_CACHE_SENTINEL_HOST, port: PORT1 },
- { host: REDIS_CACHE_SENTINEL_HOST2, port: PORT2 }
- ]
- gitlab_rails['redis_queues_sentinels'] = [
- { host: REDIS_QUEUES_SENTINEL_HOST, port: PORT1 },
- { host: REDIS_QUEUES_SENTINEL_HOST2, port: PORT2 }
- ]
- gitlab_rails['redis_shared_state_sentinels'] = [
- { host: SHARED_STATE_SENTINEL_HOST, port: PORT1 },
- { host: SHARED_STATE_SENTINEL_HOST2, port: PORT2 }
- ]
- ```
+ ```ruby
+ gitlab_rails['redis_cache_sentinels'] = [
+ { host: REDIS_CACHE_SENTINEL_HOST, port: PORT1 },
+ { host: REDIS_CACHE_SENTINEL_HOST2, port: PORT2 }
+ ]
+ gitlab_rails['redis_queues_sentinels'] = [
+ { host: REDIS_QUEUES_SENTINEL_HOST, port: PORT1 },
+ { host: REDIS_QUEUES_SENTINEL_HOST2, port: PORT2 }
+ ]
+ gitlab_rails['redis_shared_state_sentinels'] = [
+ { host: SHARED_STATE_SENTINEL_HOST, port: PORT1 },
+ { host: SHARED_STATE_SENTINEL_HOST2, port: PORT2 }
+ ]
+ ```
+
1. Note that for each persistence class, GitLab will default to using the
configuration specified in `gitlab_rails['redis_sentinels']` unless
overridden by the settings above.
@@ -879,12 +886,12 @@ in order for the HA setup to work as expected.
Before proceeding with the troubleshooting below, check your firewall rules:
- Redis machines
- - Accept TCP connection in `6379`
- - Connect to the other Redis machines via TCP in `6379`
+ - Accept TCP connection in `6379`
+ - Connect to the other Redis machines via TCP in `6379`
- Sentinel machines
- - Accept TCP connection in `26379`
- - Connect to other Sentinel machines via TCP in `26379`
- - Connect to the Redis machines via TCP in `6379`
+ - Accept TCP connection in `26379`
+ - Connect to other Sentinel machines via TCP in `26379`
+ - Connect to the Redis machines via TCP in `6379`
### Troubleshooting Redis replication
@@ -952,38 +959,38 @@ To make sure your configuration is correct:
1. SSH into your GitLab application server
1. Enter the Rails console:
- ```
- # For Omnibus installations
- sudo gitlab-rails console
+ ```
+ # For Omnibus installations
+ sudo gitlab-rails console
- # For source installations
- sudo -u git rails console production
- ```
+ # For source installations
+ sudo -u git rails console production
+ ```
1. Run in the console:
- ```ruby
- redis = Redis.new(Gitlab::Redis::SharedState.params)
- redis.info
- ```
+ ```ruby
+ redis = Redis.new(Gitlab::Redis::SharedState.params)
+ redis.info
+ ```
- Keep this screen open and try to simulate a failover below.
+ Keep this screen open and try to simulate a failover below.
1. To simulate a failover on master Redis, SSH into the Redis server and run:
- ```bash
- # port must match your master redis port, and the sleep time must be a few seconds bigger than defined one
- redis-cli -h localhost -p 6379 DEBUG sleep 20
- ```
+ ```bash
+ # port must match your master redis port, and the sleep time must be a few seconds bigger than defined one
+ redis-cli -h localhost -p 6379 DEBUG sleep 20
+ ```
1. Then back in the Rails console from the first step, run:
- ```
- redis.info
- ```
+ ```
+ redis.info
+ ```
- You should see a different port after a few seconds delay
- (the failover/reconnect time).
+ You should see a different port after a few seconds delay
+ (the failover/reconnect time).
## Changelog
diff --git a/doc/administration/high_availability/redis_source.md b/doc/administration/high_availability/redis_source.md
index be6b547372a..63915e5d96c 100644
--- a/doc/administration/high_availability/redis_source.md
+++ b/doc/administration/high_availability/redis_source.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Configuring non-Omnibus Redis for GitLab HA
This is the documentation for configuring a Highly Available Redis setup when
@@ -49,22 +53,22 @@ Assuming that the Redis master instance IP is `10.0.0.1`:
1. [Install Redis](../../install/installation.md#7-redis).
1. Edit `/etc/redis/redis.conf`:
- ```conf
- ## Define a `bind` address pointing to a local IP that your other machines
- ## can reach you. If you really need to bind to an external accessible IP, make
- ## sure you add extra firewall rules to prevent unauthorized access:
- bind 10.0.0.1
+ ```conf
+ ## Define a `bind` address pointing to a local IP that your other machines
+ ## can reach you. If you really need to bind to an external accessible IP, make
+ ## sure you add extra firewall rules to prevent unauthorized access:
+ bind 10.0.0.1
- ## Define a `port` to force redis to listen on TCP so other machines can
- ## connect to it (default port is `6379`).
- port 6379
+ ## Define a `port` to force redis to listen on TCP so other machines can
+ ## connect to it (default port is `6379`).
+ port 6379
- ## Set up password authentication (use the same password in all nodes).
- ## The password should be defined equal for both `requirepass` and `masterauth`
- ## when setting up Redis to use with Sentinel.
- requirepass redis-password-goes-here
- masterauth redis-password-goes-here
- ```
+ ## Set up password authentication (use the same password in all nodes).
+ ## The password should be defined equal for both `requirepass` and `masterauth`
+ ## when setting up Redis to use with Sentinel.
+ requirepass redis-password-goes-here
+ masterauth redis-password-goes-here
+ ```
1. Restart the Redis service for the changes to take effect.
@@ -75,25 +79,25 @@ Assuming that the Redis slave instance IP is `10.0.0.2`:
1. [Install Redis](../../install/installation.md#7-redis).
1. Edit `/etc/redis/redis.conf`:
- ```conf
- ## Define a `bind` address pointing to a local IP that your other machines
- ## can reach you. If you really need to bind to an external accessible IP, make
- ## sure you add extra firewall rules to prevent unauthorized access:
- bind 10.0.0.2
+ ```conf
+ ## Define a `bind` address pointing to a local IP that your other machines
+ ## can reach you. If you really need to bind to an external accessible IP, make
+ ## sure you add extra firewall rules to prevent unauthorized access:
+ bind 10.0.0.2
- ## Define a `port` to force redis to listen on TCP so other machines can
- ## connect to it (default port is `6379`).
- port 6379
+ ## Define a `port` to force redis to listen on TCP so other machines can
+ ## connect to it (default port is `6379`).
+ port 6379
- ## Set up password authentication (use the same password in all nodes).
- ## The password should be defined equal for both `requirepass` and `masterauth`
- ## when setting up Redis to use with Sentinel.
- requirepass redis-password-goes-here
- masterauth redis-password-goes-here
+ ## Set up password authentication (use the same password in all nodes).
+ ## The password should be defined equal for both `requirepass` and `masterauth`
+ ## when setting up Redis to use with Sentinel.
+ requirepass redis-password-goes-here
+ masterauth redis-password-goes-here
- ## Define `slaveof` pointing to the Redis master instance with IP and port.
- slaveof 10.0.0.1 6379
- ```
+ ## Define `slaveof` pointing to the Redis master instance with IP and port.
+ slaveof 10.0.0.1 6379
+ ```
1. Restart the Redis service for the changes to take effect.
1. Go through the steps again for all the other slave nodes.
@@ -110,56 +114,57 @@ master with IP `10.0.0.1` (some settings might overlap with the master):
1. [Install Redis Sentinel](https://redis.io/topics/sentinel)
1. Edit `/etc/redis/sentinel.conf`:
- ```conf
- ## Define a `bind` address pointing to a local IP that your other machines
- ## can reach you. If you really need to bind to an external accessible IP, make
- ## sure you add extra firewall rules to prevent unauthorized access:
- bind 10.0.0.1
-
- ## Define a `port` to force Sentinel to listen on TCP so other machines can
- ## connect to it (default port is `6379`).
- port 26379
-
- ## Set up password authentication (use the same password in all nodes).
- ## The password should be defined equal for both `requirepass` and `masterauth`
- ## when setting up Redis to use with Sentinel.
- requirepass redis-password-goes-here
- masterauth redis-password-goes-here
-
- ## Define with `sentinel auth-pass` the same shared password you have
- ## defined for both Redis master and slaves instances.
- sentinel auth-pass gitlab-redis redis-password-goes-here
-
- ## Define with `sentinel monitor` the IP and port of the Redis
- ## master node, and the quorum required to start a failover.
- sentinel monitor gitlab-redis 10.0.0.1 6379 2
-
- ## Define with `sentinel down-after-milliseconds` the time in `ms`
- ## that an unresponsive server will be considered down.
- sentinel down-after-milliseconds gitlab-redis 10000
-
- ## Define a value for `sentinel failover_timeout` in `ms`. This has multiple
- ## meanings:
- ##
- ## * The time needed to re-start a failover after a previous failover was
- ## already tried against the same master by a given Sentinel, is two
- ## times the failover timeout.
- ##
- ## * The time needed for a slave replicating to a wrong master according
- ## to a Sentinel current configuration, to be forced to replicate
- ## with the right master, is exactly the failover timeout (counting since
- ## the moment a Sentinel detected the misconfiguration).
- ##
- ## * The time needed to cancel a failover that is already in progress but
- ## did not produced any configuration change (SLAVEOF NO ONE yet not
- ## acknowledged by the promoted slave).
- ##
- ## * The maximum time a failover in progress waits for all the slaves to be
- ## reconfigured as slaves of the new master. However even after this time
- ## the slaves will be reconfigured by the Sentinels anyway, but not with
- ## the exact parallel-syncs progression as specified.
- sentinel failover_timeout 30000
- ```
+ ```conf
+ ## Define a `bind` address pointing to a local IP that your other machines
+ ## can reach you. If you really need to bind to an external accessible IP, make
+ ## sure you add extra firewall rules to prevent unauthorized access:
+ bind 10.0.0.1
+
+ ## Define a `port` to force Sentinel to listen on TCP so other machines can
+ ## connect to it (default port is `6379`).
+ port 26379
+
+ ## Set up password authentication (use the same password in all nodes).
+ ## The password should be defined equal for both `requirepass` and `masterauth`
+ ## when setting up Redis to use with Sentinel.
+ requirepass redis-password-goes-here
+ masterauth redis-password-goes-here
+
+ ## Define with `sentinel auth-pass` the same shared password you have
+ ## defined for both Redis master and slaves instances.
+ sentinel auth-pass gitlab-redis redis-password-goes-here
+
+ ## Define with `sentinel monitor` the IP and port of the Redis
+ ## master node, and the quorum required to start a failover.
+ sentinel monitor gitlab-redis 10.0.0.1 6379 2
+
+ ## Define with `sentinel down-after-milliseconds` the time in `ms`
+ ## that an unresponsive server will be considered down.
+ sentinel down-after-milliseconds gitlab-redis 10000
+
+ ## Define a value for `sentinel failover_timeout` in `ms`. This has multiple
+ ## meanings:
+ ##
+ ## * The time needed to re-start a failover after a previous failover was
+ ## already tried against the same master by a given Sentinel, is two
+ ## times the failover timeout.
+ ##
+ ## * The time needed for a slave replicating to a wrong master according
+ ## to a Sentinel current configuration, to be forced to replicate
+ ## with the right master, is exactly the failover timeout (counting since
+ ## the moment a Sentinel detected the misconfiguration).
+ ##
+ ## * The time needed to cancel a failover that is already in progress but
+ ## did not produced any configuration change (SLAVEOF NO ONE yet not
+ ## acknowledged by the promoted slave).
+ ##
+ ## * The maximum time a failover in progress waits for all the slaves to be
+ ## reconfigured as slaves of the new master. However even after this time
+ ## the slaves will be reconfigured by the Sentinels anyway, but not with
+ ## the exact parallel-syncs progression as specified.
+ sentinel failover_timeout 30000
+ ```
+
1. Restart the Redis service for the changes to take effect.
1. Go through the steps again for all the other Sentinel nodes.
@@ -180,21 +185,21 @@ setup:
[resque.yml.example][resque], and uncomment the Sentinel lines, pointing to
the correct server credentials:
- ```yaml
- # resque.yaml
- production:
- url: redis://:redi-password-goes-here@gitlab-redis/
- sentinels:
- -
- host: 10.0.0.1
- port: 26379 # point to sentinel, not to redis port
- -
- host: 10.0.0.2
- port: 26379 # point to sentinel, not to redis port
- -
- host: 10.0.0.3
- port: 26379 # point to sentinel, not to redis port
- ```
+ ```yaml
+ # resque.yaml
+ production:
+ url: redis://:redi-password-goes-here@gitlab-redis/
+ sentinels:
+ -
+ host: 10.0.0.1
+ port: 26379 # point to sentinel, not to redis port
+ -
+ host: 10.0.0.2
+ port: 26379 # point to sentinel, not to redis port
+ -
+ host: 10.0.0.3
+ port: 26379 # point to sentinel, not to redis port
+ ```
1. [Restart GitLab][restart] for the changes to take effect.
@@ -232,23 +237,23 @@ or a failover promotes a different **Master** node.
1. In `/etc/redis/redis.conf`:
- ```conf
- bind 10.0.0.1
- port 6379
- requirepass redis-password-goes-here
- masterauth redis-password-goes-here
- ```
+ ```conf
+ bind 10.0.0.1
+ port 6379
+ requirepass redis-password-goes-here
+ masterauth redis-password-goes-here
+ ```
1. In `/etc/redis/sentinel.conf`:
- ```conf
- bind 10.0.0.1
- port 26379
- sentinel auth-pass gitlab-redis redis-password-goes-here
- sentinel monitor gitlab-redis 10.0.0.1 6379 2
- sentinel down-after-milliseconds gitlab-redis 10000
- sentinel failover_timeout 30000
- ```
+ ```conf
+ bind 10.0.0.1
+ port 26379
+ sentinel auth-pass gitlab-redis redis-password-goes-here
+ sentinel monitor gitlab-redis 10.0.0.1 6379 2
+ sentinel down-after-milliseconds gitlab-redis 10000
+ sentinel failover_timeout 30000
+ ```
1. Restart the Redis service for the changes to take effect.
@@ -256,24 +261,24 @@ or a failover promotes a different **Master** node.
1. In `/etc/redis/redis.conf`:
- ```conf
- bind 10.0.0.2
- port 6379
- requirepass redis-password-goes-here
- masterauth redis-password-goes-here
- slaveof 10.0.0.1 6379
- ```
+ ```conf
+ bind 10.0.0.2
+ port 6379
+ requirepass redis-password-goes-here
+ masterauth redis-password-goes-here
+ slaveof 10.0.0.1 6379
+ ```
1. In `/etc/redis/sentinel.conf`:
- ```conf
- bind 10.0.0.2
- port 26379
- sentinel auth-pass gitlab-redis redis-password-goes-here
- sentinel monitor gitlab-redis 10.0.0.1 6379 2
- sentinel down-after-milliseconds gitlab-redis 10000
- sentinel failover_timeout 30000
- ```
+ ```conf
+ bind 10.0.0.2
+ port 26379
+ sentinel auth-pass gitlab-redis redis-password-goes-here
+ sentinel monitor gitlab-redis 10.0.0.1 6379 2
+ sentinel down-after-milliseconds gitlab-redis 10000
+ sentinel failover_timeout 30000
+ ```
1. Restart the Redis service for the changes to take effect.
@@ -281,24 +286,24 @@ or a failover promotes a different **Master** node.
1. In `/etc/redis/redis.conf`:
- ```conf
- bind 10.0.0.3
- port 6379
- requirepass redis-password-goes-here
- masterauth redis-password-goes-here
- slaveof 10.0.0.1 6379
- ```
+ ```conf
+ bind 10.0.0.3
+ port 6379
+ requirepass redis-password-goes-here
+ masterauth redis-password-goes-here
+ slaveof 10.0.0.1 6379
+ ```
1. In `/etc/redis/sentinel.conf`:
- ```conf
- bind 10.0.0.3
- port 26379
- sentinel auth-pass gitlab-redis redis-password-goes-here
- sentinel monitor gitlab-redis 10.0.0.1 6379 2
- sentinel down-after-milliseconds gitlab-redis 10000
- sentinel failover_timeout 30000
- ```
+ ```conf
+ bind 10.0.0.3
+ port 26379
+ sentinel auth-pass gitlab-redis redis-password-goes-here
+ sentinel monitor gitlab-redis 10.0.0.1 6379 2
+ sentinel down-after-milliseconds gitlab-redis 10000
+ sentinel failover_timeout 30000
+ ```
1. Restart the Redis service for the changes to take effect.
@@ -306,20 +311,20 @@ or a failover promotes a different **Master** node.
1. Edit `/home/git/gitlab/config/resque.yml`:
- ```yaml
- production:
- url: redis://:redi-password-goes-here@gitlab-redis/
- sentinels:
- -
- host: 10.0.0.1
- port: 26379 # point to sentinel, not to redis port
- -
- host: 10.0.0.2
- port: 26379 # point to sentinel, not to redis port
- -
- host: 10.0.0.3
- port: 26379 # point to sentinel, not to redis port
- ```
+ ```yaml
+ production:
+ url: redis://:redi-password-goes-here@gitlab-redis/
+ sentinels:
+ -
+ host: 10.0.0.1
+ port: 26379 # point to sentinel, not to redis port
+ -
+ host: 10.0.0.2
+ port: 26379 # point to sentinel, not to redis port
+ -
+ host: 10.0.0.3
+ port: 26379 # point to sentinel, not to redis port
+ ```
1. [Restart GitLab][restart] for the changes to take effect.
diff --git a/doc/administration/housekeeping.md b/doc/administration/housekeeping.md
index 1b01419e062..abe39d188aa 100644
--- a/doc/administration/housekeeping.md
+++ b/doc/administration/housekeeping.md
@@ -2,7 +2,6 @@
> [Introduced][ce-2371] in GitLab 8.4.
----
## Automatic housekeeping
GitLab automatically runs `git gc` and `git repack` on repositories
@@ -32,8 +31,6 @@ the `pushes_since_gc` value is 200 a `git gc` will be run.
You can find this option under your project's **Settings > General > Advanced**.
----
-
![Housekeeping settings](img/housekeeping_settings.png)
[ce-2371]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2371 "Housekeeping merge request"
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 6dab46cbe6f..c2ac063ce37 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -1,6 +1,7 @@
# PlantUML & GitLab
-> [Introduced][ce-8537] in GitLab 8.16.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8537) in
+> GitLab 8.16.
When [PlantUML](http://plantuml.com) integration is enabled and configured in
GitLab we are able to create simple diagrams in AsciiDoc and Markdown documents
@@ -15,7 +16,9 @@ server that will generate the diagrams.
With Docker, you can just run a container like this:
-`docker run -d --name plantuml -p 8080:8080 plantuml/plantuml-server:tomcat`
+```sh
+docker run -d --name plantuml -p 8080:8080 plantuml/plantuml-server:tomcat
+```
The **PlantUML URL** will be the hostname of the server running the container.
@@ -26,7 +29,7 @@ own PlantUML server is easy in Debian/Ubuntu distributions using Tomcat.
First you need to create a `plantuml.war` file from the source code:
-```
+```sh
sudo apt-get install graphviz openjdk-8-jdk git-core maven
git clone https://github.com/plantuml/plantuml-server.git
cd plantuml-server
@@ -36,7 +39,7 @@ mvn package
The above sequence of commands will generate a WAR file that can be deployed
using Tomcat:
-```
+```sh
sudo apt-get install tomcat7
sudo cp target/plantuml.war /var/lib/tomcat7/webapps/plantuml.war
sudo chown tomcat7:tomcat7 /var/lib/tomcat7/webapps/plantuml.war
@@ -46,7 +49,7 @@ sudo service tomcat7 restart
Once the Tomcat service restarts the PlantUML service will be ready and
listening for requests on port 8080:
-```
+```text
http://localhost:8080/plantuml
```
@@ -57,9 +60,10 @@ you can change these defaults by editing the `/etc/tomcat7/server.xml` file.
You need to enable PlantUML integration from Settings under Admin Area. To do
that, login with an Admin account and do following:
-- in GitLab go to **Admin Area**->**Settings**->**Integrations**->**PlantUML**
-- check **Enable PlantUML** checkbox
-- set the PlantUML instance as **PlantUML URL**
+- In GitLab, go to **Admin Area > Settings > Integrations**.
+- Expand the **PlantUML** section.
+- Check **Enable PlantUML** checkbox.
+- Set the PlantUML instance as **PlantUML URL**.
## Creating Diagrams
@@ -68,7 +72,6 @@ our AsciiDoc snippets, wikis and repos using delimited blocks:
- **Markdown**
- <pre>
````markdown
```plantuml
Bob -> Alice : hello
@@ -78,23 +81,23 @@ our AsciiDoc snippets, wikis and repos using delimited blocks:
- **AsciiDoc**
- ```
- [plantuml, format="png", id="myDiagram", width="200px"]
- ----
- Bob->Alice : hello
- Alice -> Bob : Go Away
- ----
- ```
+ ```text
+ [plantuml, format="png", id="myDiagram", width="200px"]
+ ----
+ Bob->Alice : hello
+ Alice -> Bob : Go Away
+ ----
+ ```
- **reStructuredText**
- ```
- .. plantuml::
- :caption: Caption with **bold** and *italic*
+ ```text
+ .. plantuml::
+ :caption: Caption with **bold** and *italic*
- Bob -> Alice: hello
- Alice -> Bob: Go Away
- ```
+ Bob -> Alice: hello
+ Alice -> Bob: Go Away
+ ```
You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.org/project/sphinxcontrib-plantuml/), but please note that we currently only support the `caption` option.
@@ -120,5 +123,3 @@ Some parameters can be added to the AsciiDoc block definition:
- *height*: Height attribute added to the img tag.
Markdown does not support any parameters and will always use PNG format.
-
-[ce-8537]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8537
diff --git a/doc/administration/integration/terminal.md b/doc/administration/integration/terminal.md
index c34858cd0db..24c9cc0bea9 100644
--- a/doc/administration/integration/terminal.md
+++ b/doc/administration/integration/terminal.md
@@ -41,9 +41,9 @@ detail below.
- Every session URL that is created has an authorization header that needs to be sent, to establish a `wss` connection.
- The session URL is not exposed to the users in any way. GitLab holds all the state internally and proxies accordingly.
-## Enabling and disabling terminal support
+## Enabling and disabling terminal support
-NOTE: **Note:** AWS Elastic Load Balancers (ELBs) do not support web sockets.
+NOTE: **Note:** AWS Elastic Load Balancers (ELBs) do not support web sockets.
AWS Application Load Balancers (ALBs) must be used if you want web terminals
to work. See [AWS Elastic Load Balancing Product Comparison](https://aws.amazon.com/elasticloadbalancing/features/#compare)
for more information.
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index 9df7b2526e2..5490a59ceac 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -13,8 +13,6 @@ if you want to know how to disable it.
To disable artifacts site-wide, follow the steps below.
----
-
**In Omnibus installations:**
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
@@ -25,8 +23,6 @@ To disable artifacts site-wide, follow the steps below.
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
----
-
**In installations from source:**
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
@@ -49,8 +45,6 @@ this is done when the job succeeds, but can also be done on failure, or always,
To change the location where the artifacts are stored locally, follow the steps
below.
----
-
**In Omnibus installations:**
_The artifacts are stored by default in
@@ -65,8 +59,6 @@ _The artifacts are stored by default in
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
----
-
**In installations from source:**
_The artifacts are stored by default in
@@ -167,8 +159,6 @@ _The artifacts are stored by default in
gitlab-rake gitlab:artifacts:migrate
```
----
-
**In installations from source:**
_The artifacts are stored by default in
@@ -207,8 +197,6 @@ right after that date passes. Artifacts are cleaned up by the
To change the default schedule on which the artifacts are expired, follow the
steps below.
----
-
**In Omnibus installations:**
1. Edit `/etc/gitlab/gitlab.rb` and comment out or add the following line
@@ -219,8 +207,6 @@ steps below.
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
----
-
**In installations from source:**
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
@@ -240,8 +226,6 @@ steps below.
To disable [the dependencies validation](../ci/yaml/README.md#when-a-dependent-job-will-fail),
you can flip the feature flag from a Rails console.
----
-
**In Omnibus installations:**
1. Enter the Rails console:
@@ -256,8 +240,6 @@ you can flip the feature flag from a Rails console.
Feature.enable('ci_disable_validates_dependencies')
```
----
-
**In installations from source:**
1. Enter the Rails console:
diff --git a/doc/administration/monitoring/performance/gitlab_configuration.md b/doc/administration/monitoring/performance/gitlab_configuration.md
index 771584268d9..9a25cc04ee7 100644
--- a/doc/administration/monitoring/performance/gitlab_configuration.md
+++ b/doc/administration/monitoring/performance/gitlab_configuration.md
@@ -8,12 +8,8 @@ The minimum required settings you need to set are the InfluxDB host and port.
Make sure _Enable InfluxDB Metrics_ is checked and hit **Save** to save the
changes.
----
-
![GitLab Performance Monitoring Admin Settings](img/metrics_gitlab_configuration_settings.png)
----
-
Finally, a restart of all GitLab processes is required for the changes to take
effect:
@@ -30,8 +26,6 @@ sudo service gitlab restart
When any migrations are pending, the metrics are disabled until the migrations
have been performed.
----
-
Read more on:
- [Introduction to GitLab Performance Monitoring](introduction.md)
diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md
index 95f497a1470..4ee156fdc11 100644
--- a/doc/administration/monitoring/performance/performance_bar.md
+++ b/doc/administration/monitoring/performance/performance_bar.md
@@ -40,10 +40,6 @@ display it.
You can toggle the Bar using the same shortcut.
----
-
![GitLab Performance Bar Admin Settings](img/performance_bar_configuration_settings.png)
----
-
[Gitaly]: ../../gitaly/index.md
diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md
index 341ea3330d7..c8968c51393 100644
--- a/doc/administration/monitoring/prometheus/index.md
+++ b/doc/administration/monitoring/prometheus/index.md
@@ -134,17 +134,57 @@ To use an external Prometheus server:
```yaml
scrape_configs:
- - job_name: 'gitlab_exporters'
+ - job_name: nginx
static_configs:
- - targets: ['1.1.1.1:9168', '1.1.1.1:9236', '1.1.1.1:9236', '1.1.1.1:9100', '1.1.1.1:9121', '1.1.1.1:9187']
-
- - job_name: 'gitlab_metrics'
- metrics_path: /-/metrics
+ - targets:
+ - 1.1.1.1:8060
+ - job_name: redis
+ static_configs:
+ - targets:
+ - 1.1.1.1:9121
+ - job_name: postgres
+ static_configs:
+ - targets:
+ - 1.1.1.1:9187
+ - job_name: node
+ static_configs:
+ - targets:
+ - 1.1.1.1:9100
+ - job_name: gitlab-workhorse
+ static_configs:
+ - targets:
+ - 1.1.1.1:9229
+ - job_name: gitlab-rails
+ metrics_path: "/-/metrics"
+ static_configs:
+ - targets:
+ - 1.1.1.1:8080
+ - job_name: gitlab-sidekiq
+ static_configs:
+ - targets:
+ - 1.1.1.1:8082
+ - job_name: gitlab_monitor_database
+ metrics_path: "/database"
+ static_configs:
+ - targets:
+ - 1.1.1.1:9168
+ - job_name: gitlab_monitor_sidekiq
+ metrics_path: "/sidekiq"
+ static_configs:
+ - targets:
+ - 1.1.1.1:9168
+ - job_name: gitlab_monitor_process
+ metrics_path: "/process"
+ static_configs:
+ - targets:
+ - 1.1.1.1:9168
+ - job_name: gitaly
static_configs:
- - targets: ['1.1.1.1:443']
+ - targets:
+ - 1.1.1.1:9236
```
-1. Restart the Prometheus server.
+1. Reload the Prometheus server.
## Viewing performance metrics
diff --git a/doc/administration/operations/filesystem_benchmarking.md b/doc/administration/operations/filesystem_benchmarking.md
index 4a6e22bdb84..b5922d9d99d 100644
--- a/doc/administration/operations/filesystem_benchmarking.md
+++ b/doc/administration/operations/filesystem_benchmarking.md
@@ -106,9 +106,9 @@ important metric is the `real` time.
```sh
$ time for i in {0..1000}; do echo 'test' > "test${i}.txt"; done
-real 0m0.116s
-user 0m0.025s
-sys 0m0.091s
+real 0m0.116s
+user 0m0.025s
+sys 0m0.091s
$ time for i in {0..1000}; do cat "test${i}.txt" > /dev/null; done
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index b5b8f124274..3cabe8eb16e 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -256,7 +256,7 @@ world. Custom domains and TLS are supported.
### Custom domain verification
To prevent malicious users from hijacking domains that don't belong to them,
-GitLab supports [custom domain verification](../../user/project/pages/getting_started_part_three.md#dns-txt-record).
+GitLab supports [custom domain verification](../../user/project/pages/custom_domains_ssl_tls_certification/index.md#steps).
When adding a custom domain, users will be required to prove they own it by
adding a GitLab-controlled verification code to the DNS records for that domain.
diff --git a/doc/administration/pseudonymizer.md b/doc/administration/pseudonymizer.md
index 78b2751da13..716a4259a64 100644
--- a/doc/administration/pseudonymizer.md
+++ b/doc/administration/pseudonymizer.md
@@ -65,8 +65,8 @@ To configure the pseudonymizer, you need to:
```yaml
pseudonymizer:
- manifest: config/pseudonymizer.yml
- upload:
+ manifest: config/pseudonymizer.yml
+ upload:
remote_directory: 'gitlab-elt' # bucket name
connection:
provider: AWS
diff --git a/doc/administration/raketasks/geo.md b/doc/administration/raketasks/geo.md
index 435aed8c413..691d34ab7fa 100644
--- a/doc/administration/raketasks/geo.md
+++ b/doc/administration/raketasks/geo.md
@@ -2,7 +2,7 @@
## Git housekeeping
-There are few tasks you can run to schedule a git housekeeping to start at the
+There are few tasks you can run to schedule a git housekeeping to start at the
next repository sync in a **Secondary node**:
### Incremental Repack
@@ -23,7 +23,7 @@ sudo -u git -H bundle exec rake geo:git:housekeeping:incremental_repack RAILS_EN
### Full Repack
-This is equivalent of running `git repack -d -A --pack-kept-objects` on a
+This is equivalent of running `git repack -d -A --pack-kept-objects` on a
_bare_ repository which will optionally, write a reachability bitmap index
when this is enabled in GitLab.
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index 2b31233d429..8d0b5b42515 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -251,3 +251,22 @@ sudo gitlab-rake gitlab:exclusive_lease:clear[project_housekeeping:*]
# to clear a lease for repository garbage collection in a specific project: (id=4)
sudo gitlab-rake gitlab:exclusive_lease:clear[project_housekeeping:4]
```
+
+## Display status of database migrations
+
+To check the status of migrations, you can use the following rake task:
+
+```bash
+sudo gitlab-rake db:migrate:status
+```
+
+This will output a table with a `Status` of `up` or `down` for
+each Migration ID.
+
+```bash
+database: gitlabhq_production
+
+ Status Migration ID Migration Name
+--------------------------------------------------
+ up migration_id migration_name
+``` \ No newline at end of file
diff --git a/doc/administration/raketasks/project_import_export.md b/doc/administration/raketasks/project_import_export.md
index 0599e12b913..138db4dfbb1 100644
--- a/doc/administration/raketasks/project_import_export.md
+++ b/doc/administration/raketasks/project_import_export.md
@@ -2,14 +2,14 @@
>**Note:**
>
-> - [Introduced][ce-3050] in GitLab 8.9.
-> - Importing will not be possible if the import instance version is lower
-> than that of the exporter.
-> - For existing installations, the project import option has to be enabled in
-> application settings (`/admin/application_settings`) under 'Import sources'.
-> - The exports are stored in a temporary [shared directory][tmp] and are deleted
-> every 24 hours by a specific worker.
-> - ImportExport can use object storage automatically starting from GitLab 11.3
+> - [Introduced][ce-3050] in GitLab 8.9.
+> - Importing will not be possible if the import instance version is lower
+> than that of the exporter.
+> - For existing installations, the project import option has to be enabled in
+> application settings (`/admin/application_settings`) under 'Import sources'.
+> - The exports are stored in a temporary [shared directory][tmp] and are deleted
+> every 24 hours by a specific worker.
+> - ImportExport can use object storage automatically starting from GitLab 11.3
The GitLab Import/Export version can be checked by using:
diff --git a/doc/administration/raketasks/storage.md b/doc/administration/raketasks/storage.md
index 42a1a1c2e60..2f83dd17d9f 100644
--- a/doc/administration/raketasks/storage.md
+++ b/doc/administration/raketasks/storage.md
@@ -1,17 +1,17 @@
# Repository Storage Rake Tasks
-This is a collection of rake tasks you can use to help you list and migrate
-existing projects and attachments associated with it from Legacy storage to
+This is a collection of rake tasks you can use to help you list and migrate
+existing projects and attachments associated with it from Legacy storage to
the new Hashed storage type.
You can read more about the storage types [here][storage-types].
## Migrate existing projects to Hashed storage
-Before migrating your existing projects, you should
+Before migrating your existing projects, you should
[enable hashed storage][storage-migration] for the new projects as well.
-This task will schedule all your existing projects and attachments associated with it to be migrated to the
+This task will schedule all your existing projects and attachments associated with it to be migrated to the
**Hashed** storage type:
**Omnibus Installation**
@@ -30,15 +30,15 @@ They both also accept a range as environment variable:
```bash
# to migrate any non migrated project from ID 20 to 50.
-export ID_FROM=20
+export ID_FROM=20
export ID_TO=50
```
You can monitor the progress in the **Admin Area > Monitoring > Background Jobs** page.
-There is a specific Queue you can watch to see how long it will take to finish:
+There is a specific Queue you can watch to see how long it will take to finish:
`hashed_storage:hashed_storage_project_migrate`
-After it reaches zero, you can confirm every project has been migrated by running the commands bellow.
+After it reaches zero, you can confirm every project has been migrated by running the commands bellow.
If you find it necessary, you can run this migration script again to schedule missing projects.
Any error or warning will be logged in Sidekiq's log file.
@@ -55,7 +55,7 @@ If you need to rollback the storage migration for any reason, you can follow the
NOTE: **Note:** Hashed Storage will be required in future version of GitLab.
-To prevent new projects from being created in the Hashed storage,
+To prevent new projects from being created in the Hashed storage,
you need to undo the [enable hashed storage][storage-migration] changes.
This task will schedule all your existing projects and associated attachments to be rolled back to the
@@ -77,15 +77,14 @@ Both commands accept a range as environment variable:
```bash
# to rollback any migrated project from ID 20 to 50.
-export ID_FROM=20
+export ID_FROM=20
export ID_TO=50
```
You can monitor the progress in the **Admin Area > Monitoring > Background Jobs** page.
On the **Queues** tab, you can watch the `hashed_storage:hashed_storage_project_rollback` queue to see how long the process will take to finish.
-
-After it reaches zero, you can confirm every project has been rolled back by running the commands bellow.
+After it reaches zero, you can confirm every project has been rolled back by running the commands bellow.
If some projects weren't rolled back, you can run this rollback script again to schedule further rollbacks.
Any error or warning will be logged in Sidekiq's log file.
@@ -106,7 +105,7 @@ sudo gitlab-rake gitlab:storage:legacy_projects
sudo -u git -H bundle exec rake gitlab:storage:legacy_projects RAILS_ENV=production
```
-------
+---
To list projects using **Legacy** storage:
@@ -139,7 +138,7 @@ sudo gitlab-rake gitlab:storage:hashed_projects
sudo -u git -H bundle exec rake gitlab:storage:hashed_projects RAILS_ENV=production
```
-------
+---
To list projects using **Hashed** storage:
@@ -171,7 +170,7 @@ sudo gitlab-rake gitlab:storage:legacy_attachments
sudo -u git -H bundle exec rake gitlab:storage:legacy_attachments RAILS_ENV=production
```
-------
+---
To list project attachments using **Legacy** storage:
@@ -203,7 +202,7 @@ sudo gitlab-rake gitlab:storage:hashed_attachments
sudo -u git -H bundle exec rake gitlab:storage:hashed_attachments RAILS_ENV=production
```
-------
+---
To list project attachments using **Hashed** storage:
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index 3de860f9240..ad3a9b19c3c 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -55,8 +55,6 @@ storage2:
> don't specify the full repository path but the parent path), but not for source
> installations.
----
-
Now that you've read that big fat warning above, let's edit the configuration
files and add the full paths of the alternative repository storage paths. In
the example below, we add two more mountpoints that are named `nfs` and `cephfs`
@@ -90,8 +88,6 @@ are upgrading from a version prior to 8.10, make sure to add the configuration
as described in the step above. After you make the changes and confirm they are
working, you can remove the `repos_path` line.
----
-
**For Omnibus installations**
1. Edit `/etc/gitlab/gitlab.rb` by appending the rest of the paths to the
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index c6529812ec3..51e267c865e 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -1,21 +1,18 @@
# Uploads administration
->**Notes:**
Uploads represent all user data that may be sent to GitLab as a single file. As an example, avatars and notes' attachments are uploads. Uploads are integral to GitLab functionality, and therefore cannot be disabled.
## Using local storage
->**Notes:**
+NOTE: **Note:**
This is the default configuration
To change the location where the uploads are stored locally, follow the steps
below.
----
-
**In Omnibus installations:**
->**Notes:**
+NOTE: **Note:**
For historical reasons, uploads are stored into a base directory, which by default is `uploads/-/system`. It is strongly discouraged to change this configuration option on an existing GitLab installation.
_The uploads are stored by default in `/var/opt/gitlab/gitlab-rails/uploads`._
@@ -30,8 +27,6 @@ _The uploads are stored by default in `/var/opt/gitlab/gitlab-rails/uploads`._
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
----
-
**In installations from source:**
_The uploads are stored by default in
@@ -42,8 +37,8 @@ _The uploads are stored by default in
```yaml
uploads:
- storage_path: /mnt/storage
- base_dir: uploads
+ storage_path: /mnt/storage
+ base_dir: uploads
```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -108,8 +103,8 @@ _The uploads are stored by default in
}
```
- >**Note:**
- >If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
+ NOTE: **Note:**
+ If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
```ruby
gitlab_rails['uploads_object_store_connection'] = {
@@ -122,8 +117,6 @@ _The uploads are stored by default in
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate` rake task](raketasks/uploads/migrate.md).
----
-
**In installations from source:**
_The uploads are stored by default in
@@ -147,6 +140,75 @@ _The uploads are stored by default in
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate` rake task](raketasks/uploads/migrate.md).
+### OpenStack compatible connection settings
+
+The connection settings match those provided by [Fog](https://github.com/fog), and are as follows:
+
+| Setting | Description | Default |
+|---------|-------------|---------|
+| `provider` | Always `OpenStack` for compatible hosts | OpenStack |
+| `openstack_username` | OpenStack username | |
+| `openstack_api_key` | OpenStack api key | |
+| `openstack_temp_url_key` | OpenStack key for generating temporary urls | |
+| `openstack_auth_url` | OpenStack authentication endpont | |
+| `openstack_region` | OpenStack region | |
+| `openstack_tenant` | OpenStack tenant ID |
+
+**In Omnibus installations:**
+
+_The uploads are stored by default in
+`/var/opt/gitlab/gitlab-rails/public/uploads/-/system`._
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
+ the values you want:
+
+ ```ruby
+ gitlab_rails['uploads_object_store_remote_directory'] = "OPENSTACK_OBJECT_CONTAINER_NAME"
+ gitlab_rails['uploads_object_store_connection'] = {
+ 'provider' => 'OpenStack',
+ 'openstack_username' => 'OPENSTACK_USERNAME',
+ 'openstack_api_key' => 'OPENSTACK_PASSWORD',
+ 'openstack_temp_url_key' => 'OPENSTACK_TEMP_URL_KEY',
+ 'openstack_auth_url' => 'https://auth.cloud.ovh.net/v2.0/',
+ 'openstack_region' => 'DE1',
+ 'openstack_tenant' => 'TENANT_ID',
+ }
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate` rake task](raketasks/uploads/migrate.md).
+
+---
+
+**In installations from source:**
+
+_The uploads are stored by default in
+`/home/git/gitlab/public/uploads/-/system`._
+
+1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
+ lines:
+
+ ```yaml
+ uploads:
+ object_store:
+ enabled: true
+ direct_upload: false
+ background_upload: true
+ proxy_download: false
+ remote_directory: OPENSTACK_OBJECT_CONTAINER_NAME
+ connection:
+ provider: OpenStack
+ openstack_username: OPENSTACK_USERNAME
+ openstack_api_key: OPENSTACK_PASSWORD
+ openstack_temp_url_key: OPENSTACK_TEMP_URL_KEY
+ openstack_auth_url: 'https://auth.cloud.ovh.net/v2.0/'
+ openstack_region: DE1
+ openstack_tenant: 'TENANT_ID'
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate` rake task](raketasks/uploads/migrate.md).
+
[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure "How to reconfigure Omnibus GitLab"
[restart gitlab]: restart_gitlab.md#installations-from-source "How to restart GitLab"
[eep]: https://about.gitlab.com/gitlab-ee/ "GitLab Premium"
diff --git a/doc/api/README.md b/doc/api/README.md
index b2bb55f2fcf..8e60d1c61df 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -29,6 +29,7 @@ The following API resources are available in the project context:
| [Commits](commits.md) | `/projects/:id/repository/commits`, `/projects/:id/statuses` |
| [Container Registry](container_registry.md) | `/projects/:id/registry/repositories` |
| [Custom attributes](custom_attributes.md) | `/projects/:id/custom_attributes` (also available for groups and users) |
+| [Dependencies](dependencies.md) **[ULTIMATE]** | `/projects/:id/dependencies`
| [Deploy keys](deploy_keys.md) | `/projects/:id/deploy_keys` (also available standalone) |
| [Deployments](deployments.md) | `/projects/:id/deployments` |
| [Discussions](discussions.md) (threaded comments) | `/projects/:id/issues/.../discussions`, `/projects/:id/snippets/.../discussions`, `/projects/:id/merge_requests/.../discussions`, `/projects/:id/commits/.../discussions` (also available for groups) |
@@ -321,8 +322,6 @@ By default, impersonation is enabled. To disable impersonation:
To re-enable impersonation, remove this configuration and reconfigure GitLab.
----
-
**For installations from source**
1. Edit `config/gitlab.yml`:
@@ -381,8 +380,6 @@ returned with status code `404`:
}
```
----
-
Example of a valid API call and a request using cURL with sudo request,
providing a username:
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 25015fad9e3..6eb4c47415f 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -716,6 +716,7 @@ Example response if commit is signed:
```
Example response if commit is unsigned:
+
```json
{
"message": "404 GPG Signature Not Found"
diff --git a/doc/api/dependencies.md b/doc/api/dependencies.md
new file mode 100644
index 00000000000..ed5ebdade19
--- /dev/null
+++ b/doc/api/dependencies.md
@@ -0,0 +1,50 @@
+# Dependencies API **(ULTIMATE)**
+
+CAUTION: **Caution:**
+This API is in an alpha stage and considered unstable.
+The response payload may be subject to change or breakage
+across GitLab releases.
+
+Every call to this endpoint requires authentication. To perform this call, user should be authorized to read
+[Project Security Dashboard](../user/application_security/security_dashboard/index.md#project-security-dashboard).
+
+## List project dependencies
+
+Get a list of project dependencies. This API partially mirroring
+[Dependency List](../user/application_security/dependency_scanning/index.md#dependency-list) feature.
+This list can be generated only for [languages and package managers](../user/application_security/dependency_scanning/index.md#supported-languages-and-package-managers)
+supported by Gemnasium.
+
+```
+GET /projects/:id/dependencies
+GET /projects/:id/vulnerabilities?package_manger=maven
+GET /projects/:id/vulnerabilities?package_manger=yarn,bundler
+```
+
+| Attribute | Type | Required | Description |
+| ------------- | -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `package_manager` | string array | no | Returns dependencies belonging to specified package manager. Valid values: `bundler`, `composer`, `maven`, `npm`, `pip` or `yarn`. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/dependencies
+```
+
+Example response:
+
+```json
+[
+ {
+ "name": "rails",
+ "version": "5.0.1",
+ "package_manager": "bundler",
+ "dependency_file_path": "Gemfile.lock"
+ },
+ {
+ "name": "hanami",
+ "version": "1.3.1",
+ "package_manager": "bundler",
+ "dependency_file_path": "Gemfile.lock"
+ }
+]
+```
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index 208b8dca2e2..b4a2d0b15f6 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -12,16 +12,15 @@ This includes system notes, which are notes about changes to the object (for exa
## Discussions pagination
-By default, `GET` requests return 20 results at a time because the API results
-are paginated.
+By default, `GET` requests return 20 results at a time because the API results are paginated.
Read more on [pagination](README.md#pagination).
## Issues
-### List project issue discussions
+### List project issue discussion items
-Gets a list of all discussions for a single issue.
+Gets a list of all discussion items for a single issue.
```
GET /projects/:id/issues/:issue_iid/discussions
@@ -115,9 +114,9 @@ GET /projects/:id/issues/:issue_iid/discussions
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions
```
-### Get single issue discussion
+### Get single issue discussion item
-Returns a single discussion for a specific project issue
+Returns a single discussion item for a specific project issue
```
GET /projects/:id/issues/:issue_iid/discussions/:discussion_id
@@ -129,16 +128,15 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `issue_iid` | integer | yes | The IID of an issue |
-| `discussion_id` | integer | yes | The ID of a discussion |
+| `discussion_id` | integer | yes | The ID of a discussion item |
```bash
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
-### Create new issue discussion
+### Create new issue thread
-Creates a new discussion to a single project issue. This is similar to creating
-a note but other comments (replies) can be added to it later.
+Creates a new thread to a single project issue. This is similar to creating a note but other comments (replies) can be added to it later.
```
POST /projects/:id/issues/:issue_iid/discussions
@@ -150,17 +148,19 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `issue_iid` | integer | yes | The IID of an issue |
-| `body` | string | yes | The content of a discussion |
+| `body` | string | yes | The content of the thread |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions?body=comment
```
-### Add note to existing issue discussion
+### Add note to existing issue thread
+
+Adds a new note to the thread. This can also [create a thread from a single comment](../user/discussions/#start-a-thread-by-replying-to-a-standard-comment).
-Adds a new note to the discussion. This can also
-[create a discussion from a single comment](../user/discussions/#start-a-discussion-by-replying-to-a-standard-comment).
+**WARNING**
+Notes can be added to other items than comments (system notes, etc.) making them threads.
```
POST /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes
@@ -172,18 +172,18 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `issue_iid` | integer | yes | The IID of an issue |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of the note/reply |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
-### Modify existing issue discussion note
+### Modify existing issue thread note
-Modify existing discussion note of an issue.
+Modify existing thread note of an issue.
```
PUT /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes/:note_id
@@ -195,17 +195,17 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `issue_iid` | integer | yes | The IID of an issue |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of the note/reply |
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
```
-### Delete an issue discussion note
+### Delete an issue thread note
-Deletes an existing discussion note of an issue.
+Deletes an existing thread note of an issue.
```
DELETE /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes/:note_id
@@ -226,9 +226,9 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitl
## Snippets
-### List project snippet discussions
+### List project snippet discussion items
-Gets a list of all discussions for a single snippet.
+Gets a list of all discussion items for a single snippet.
```
GET /projects/:id/snippets/:snippet_id/discussions
@@ -322,9 +322,9 @@ GET /projects/:id/snippets/:snippet_id/discussions
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions
```
-### Get single snippet discussion
+### Get single snippet discussion item
-Returns a single discussion for a specific project snippet
+Returns a single discussion item for a specific project snippet
```
GET /projects/:id/snippets/:snippet_id/discussions/:discussion_id
@@ -336,15 +336,15 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `snippet_id` | integer | yes | The ID of an snippet |
-| `discussion_id` | integer | yes | The ID of a discussion |
+| `discussion_id` | integer | yes | The ID of a discussion item |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
-### Create new snippet discussion
+### Create new snippet thread
-Creates a new discussion to a single project snippet. This is similar to creating
+Creates a new thread to a single project snippet. This is similar to creating
a note but other comments (replies) can be added to it later.
```
@@ -364,9 +364,9 @@ Parameters:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions?body=comment
```
-### Add note to existing snippet discussion
+### Add note to existing snippet thread
-Adds a new note to the discussion.
+Adds a new note to the thread.
```
POST /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes
@@ -378,18 +378,18 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `snippet_id` | integer | yes | The ID of an snippet |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of the note/reply |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
-### Modify existing snippet discussion note
+### Modify existing snippet thread note
-Modify existing discussion note of an snippet.
+Modify existing thread note of a snippet.
```
PUT /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id
@@ -401,17 +401,17 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `snippet_id` | integer | yes | The ID of an snippet |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of the note/reply |
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
```
-### Delete an snippet discussion note
+### Delete a snippet thread note
-Deletes an existing discussion note of an snippet.
+Deletes an existing thread note of a snippet.
```
DELETE /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id
@@ -432,9 +432,9 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitl
## Epics **(ULTIMATE)**
-### List group epic discussions
+### List group epic discussion items
-Gets a list of all discussions for a single epic.
+Gets a list of all discussion items for a single epic.
```
GET /groups/:id/epics/:epic_id/discussions
@@ -529,9 +529,9 @@ GET /groups/:id/epics/:epic_id/discussions
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions
```
-### Get single epic discussion
+### Get single epic discussion item
-Returns a single discussion for a specific group epic
+Returns a single discussion item for a specific group epic
```
GET /groups/:id/epics/:epic_id/discussions/:discussion_id
@@ -543,16 +543,16 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `epic_id` | integer | yes | The ID of an epic |
-| `discussion_id` | integer | yes | The ID of a discussion |
+| `discussion_id` | integer | yes | The ID of a discussion item |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
-### Create new epic discussion
+### Create new epic thread
-Creates a new discussion to a single group epic. This is similar to creating
-a note but but another comments (replies) can be added to it later.
+Creates a new thread to a single group epic. This is similar to creating
+a note but but other comments (replies) can be added to it later.
```
POST /groups/:id/epics/:epic_id/discussions
@@ -564,17 +564,17 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `epic_id` | integer | yes | The ID of an epic |
-| `body` | string | yes | The content of a discussion |
+| `body` | string | yes | The content of the thread |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions?body=comment
```
-### Add note to existing epic discussion
+### Add note to existing epic thread
-Adds a new note to the discussion. This can also
-[create a discussion from a single comment](../user/discussions/#start-a-discussion-by-replying-to-a-standard-comment).
+Adds a new note to the thread. This can also
+[create a thread from a single comment](../user/discussions/#start-a-thread-by-replying-to-a-standard-comment).
```
POST /groups/:id/epics/:epic_id/discussions/:discussion_id/notes
@@ -585,19 +585,19 @@ Parameters:
| Attribute | Type | Required | Description |
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
-| `epic_id` | integer | yes | The ID of an epic |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `epic_id` | integer | yes | The ID of an epic |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of the note/reply |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
-### Modify existing epic discussion note
+### Modify existing epic thread note
-Modify existing discussion note of an epic.
+Modify existing thread note of an epic.
```
PUT /groups/:id/epics/:epic_id/discussions/:discussion_id/notes/:note_id
@@ -609,17 +609,17 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `epic_id` | integer | yes | The ID of an epic |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of note/reply |
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
```
-### Delete an epic discussion note
+### Delete an epic thread note
-Deletes an existing discussion note of an epic.
+Deletes an existing thread note of an epic.
```
DELETE /groups/:id/epics/:epic_id/discussions/:discussion_id/notes/:note_id
@@ -631,8 +631,8 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `epic_id` | integer | yes | The ID of an epic |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions/636
@@ -640,9 +640,9 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitl
## Merge requests
-### List project merge request discussions
+### List project merge request discussion items
-Gets a list of all discussions for a single merge request.
+Gets a list of all discussion items for a single merge request.
```
GET /projects/:id/merge_requests/:merge_request_iid/discussions
@@ -789,9 +789,9 @@ Diff comments contain also position:
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions
```
-### Get single merge request discussion
+### Get single merge request discussion item
-Returns a single discussion for a specific project merge request
+Returns a single discussion item for a specific project merge request
```
GET /projects/:id/merge_requests/:merge_request_iid/discussions/:discussion_id
@@ -803,15 +803,15 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
-| `discussion_id` | integer | yes | The ID of a discussion |
+| `discussion_id` | integer | yes | The ID of a discussion item |
```bash
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
-### Create new merge request discussion
+### Create new merge request thread
-Creates a new discussion to a single project merge request. This is similar to creating
+Creates a new thread to a single project merge request. This is similar to creating
a note but other comments (replies) can be added to it later.
```
@@ -824,7 +824,7 @@ Parameters:
| ------------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
-| `body` | string | yes | The content of a discussion |
+| `body` | string | yes | The content of the thread |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
| `position` | hash | no | Position when creating a diff note |
| `position[base_sha]` | string | yes | Base commit SHA in the source branch |
@@ -844,9 +844,9 @@ Parameters:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions?body=comment
```
-### Resolve a merge request discussion
+### Resolve a merge request thread
-Resolve/unresolve whole discussion of a merge request.
+Resolve/unresolve whole thread of a merge request.
```
PUT /projects/:id/merge_requests/:merge_request_iid/discussions/:discussion_id
@@ -858,17 +858,17 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
-| `discussion_id` | integer | yes | The ID of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
| `resolved` | boolean | yes | Resolve/unresolve the discussion |
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7?resolved=true
```
-### Add note to existing merge request discussion
+### Add note to existing merge request thread
-Adds a new note to the discussion. This can also
-[create a discussion from a single comment](../user/discussions/#start-a-discussion-by-replying-to-a-standard-comment).
+Adds a new note to the thread. This can also
+[create a thread from a single comment](../user/discussions/#start-a-thread-by-replying-to-a-standard-comment).
```
POST /projects/:id/merge_requests/:merge_request_iid/discussions/:discussion_id/notes
@@ -880,18 +880,18 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of the note/reply |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
-### Modify an existing merge request discussion note
+### Modify an existing merge request thread note
-Modify or resolve an existing discussion note of a merge request.
+Modify or resolve an existing thread note of a merge request.
```
PUT /projects/:id/merge_requests/:merge_request_iid/discussions/:discussion_id/notes/:note_id
@@ -903,9 +903,9 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | no | The content of a discussion (exactly one of `body` or `resolved` must be set |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | no | The content of the note/reply (exactly one of `body` or `resolved` must be set |
| `resolved` | boolean | no | Resolve/unresolve the note (exactly one of `body` or `resolved` must be set |
```bash
@@ -918,9 +918,9 @@ Resolving a note:
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?resolved=true
```
-### Delete a merge request discussion note
+### Delete a merge request thread note
-Deletes an existing discussion note of a merge request.
+Deletes an existing thread note of a merge request.
```
DELETE /projects/:id/merge_requests/:merge_request_iid/discussions/:discussion_id/notes/:note_id
@@ -932,8 +932,8 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/636
@@ -941,9 +941,9 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitl
## Commits
-### List project commit discussions
+### List project commit discussion items
-Gets a list of all discussions for a single commit.
+Gets a list of all discussion items for a single commit.
```
GET /projects/:id/commits/:commit_id/discussions
@@ -1082,9 +1082,9 @@ Diff comments contain also position:
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions
```
-### Get single commit discussion
+### Get single commit discussion item
-Returns a single discussion for a specific project commit
+Returns a single discussion item for a specific project commit
```
GET /projects/:id/commits/:commit_id/discussions/:discussion_id
@@ -1096,15 +1096,15 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `commit_id` | integer | yes | The ID of a commit |
-| `discussion_id` | integer | yes | The ID of a discussion |
+| `discussion_id` | integer | yes | The ID of a discussion item |
```bash
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
-### Create new commit discussion
+### Create new commit thread
-Creates a new discussion to a single project commit. This is similar to creating
+Creates a new thread to a single project commit. This is similar to creating
a note but other comments (replies) can be added to it later.
```
@@ -1117,7 +1117,7 @@ Parameters:
| ------------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `commit_id` | integer | yes | The ID of a commit |
-| `body` | string | yes | The content of a discussion |
+| `body` | string | yes | The content of the thread |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
| `position` | hash | no | Position when creating a diff note |
| `position[base_sha]` | string | yes | Base commit SHA in the source branch |
@@ -1137,9 +1137,9 @@ Parameters:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions?body=comment
```
-### Add note to existing commit discussion
+### Add note to existing commit thread
-Adds a new note to the discussion.
+Adds a new note to the thread.
```
POST /projects/:id/commits/:commit_id/discussions/:discussion_id/notes
@@ -1151,18 +1151,18 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `commit_id` | integer | yes | The ID of a commit |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
-| `body` | string | yes | The content of a discussion |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
+| `body` | string | yes | The content of the note/reply |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
-### Modify an existing commit discussion note
+### Modify an existing commit thread note
-Modify or resolve an existing discussion note of a commit.
+Modify or resolve an existing thread note of a commit.
```
PUT /projects/:id/commits/:commit_id/discussions/:discussion_id/notes/:note_id
@@ -1174,8 +1174,8 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `commit_id` | integer | yes | The ID of a commit |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
| `body` | string | no | The content of a note |
```bash
@@ -1188,9 +1188,9 @@ Resolving a note:
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?resolved=true
```
-### Delete a commit discussion note
+### Delete a commit thread note
-Deletes an existing discussion note of a commit.
+Deletes an existing thread note of a commit.
```
DELETE /projects/:id/commits/:commit_id/discussions/:discussion_id/notes/:note_id
@@ -1202,8 +1202,8 @@ Parameters:
| ------------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `commit_id` | integer | yes | The ID of a commit |
-| `discussion_id` | integer | yes | The ID of a discussion |
-| `note_id` | integer | yes | The ID of a discussion note |
+| `discussion_id` | integer | yes | The ID of a thread |
+| `note_id` | integer | yes | The ID of a thread note |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/636
diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md
new file mode 100644
index 00000000000..31c0e6abead
--- /dev/null
+++ b/doc/api/group_clusters.md
@@ -0,0 +1,280 @@
+# Group clusters API
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30213)
+in GitLab 12.1.
+
+NOTE: **Note:**
+User will need at least maintainer access for the group to use these endpoints.
+
+## List group clusters
+
+Returns a list of group clusters.
+
+```
+GET /groups/:id/clusters
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+
+Example request:
+
+```bash
+curl --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/groups/26/clusters
+```
+
+Example response:
+
+```json
+[
+ {
+ "id":18,
+ "name":"cluster-1",
+ "domain":"example.com",
+ "created_at":"2019-01-02T20:18:12.563Z",
+ "provider_type":"user",
+ "platform_type":"kubernetes",
+ "environment_scope":"*",
+ "cluster_type":"group_type",
+ "user":
+ {
+ "id":1,
+ "name":"Administrator",
+ "username":"root",
+ "state":"active",
+ "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..",
+ "web_url":"https://gitlab.example.com/root"
+ },
+ "platform_kubernetes":
+ {
+ "api_url":"https://104.197.68.152",
+ "authorization_type":"rbac",
+ "ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
+ }
+ },
+ {
+ "id":19,
+ "name":"cluster-2",
+ ...
+ }
+]
+```
+
+## Get a single group cluster
+
+Gets a single group cluster.
+
+```
+GET /groups/:id/clusters/:cluster_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+| `cluster_id` | integer | yes | The ID of the cluster |
+
+Example request:
+
+```bash
+curl --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/groups/26/clusters/18
+```
+
+Example response:
+
+```json
+{
+ "id":18,
+ "name":"cluster-1",
+ "domain":"example.com",
+ "created_at":"2019-01-02T20:18:12.563Z",
+ "provider_type":"user",
+ "platform_type":"kubernetes",
+ "environment_scope":"*",
+ "cluster_type":"group_type",
+ "user":
+ {
+ "id":1,
+ "name":"Administrator",
+ "username":"root",
+ "state":"active",
+ "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..",
+ "web_url":"https://gitlab.example.com/root"
+ },
+ "platform_kubernetes":
+ {
+ "api_url":"https://104.197.68.152",
+ "authorization_type":"rbac",
+ "ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
+ },
+ "group":
+ {
+ "id":26,
+ "name":"group-with-clusters-api",
+ "web_url":"https://gitlab.example.com/group-with-clusters-api"
+ }
+}
+```
+
+## Add existing cluster to group
+
+Adds an existing Kubernetes cluster to the group.
+
+```
+POST /groups/:id/clusters/user
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+| `name` | String | yes | The name of the cluster |
+| `domain` | String | no | The [base domain](../user/group/clusters/index.md#base-domain) of the cluster |
+| `enabled` | Boolean | no | Determines if cluster is active or not, defaults to true |
+| `managed` | Boolean | no | Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true |
+| `platform_kubernetes_attributes[api_url]` | String | yes | The URL to access the Kubernetes API |
+| `platform_kubernetes_attributes[token]` | String | yes | The token to authenticate against Kubernetes |
+| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate |
+| `platform_kubernetes_attributes[authorization_type]` | String | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. |
+| `environment_scope` | String | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM)** |
+
+Example request:
+
+```bash
+curl --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/groups/26/clusters/user \
+-H "Accept: application/json" \
+-H "Content-Type:application/json" \
+--request POST --data '{"name":"cluster-5", "platform_kubernetes_attributes":{"api_url":"https://35.111.51.20","token":"12345","ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"}}'
+```
+
+Example response:
+
+```json
+{
+ "id":24,
+ "name":"cluster-5",
+ "created_at":"2019-01-03T21:53:40.610Z",
+ "provider_type":"user",
+ "platform_type":"kubernetes",
+ "environment_scope":"*",
+ "cluster_type":"group_type",
+ "user":
+ {
+ "id":1,
+ "name":"Administrator",
+ "username":"root",
+ "state":"active",
+ "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..",
+ "web_url":"https://gitlab.example.com/root"
+ },
+ "platform_kubernetes":
+ {
+ "api_url":"https://35.111.51.20",
+ "authorization_type":"rbac",
+ "ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
+ },
+ "group":
+ {
+ "id":26,
+ "name":"group-with-clusters-api",
+ "web_url":"https://gitlab.example.com/root/group-with-clusters-api"
+ }
+}
+```
+
+## Edit group cluster
+
+Updates an existing group cluster.
+
+```
+PUT /groups/:id/clusters/:cluster_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+| `cluster_id` | integer | yes | The ID of the cluster |
+| `name` | String | no | The name of the cluster |
+| `domain` | String | no | The [base domain](../user/group/clusters/index.md#base-domain) of the cluster |
+| `platform_kubernetes_attributes[api_url]` | String | no | The URL to access the Kubernetes API |
+| `platform_kubernetes_attributes[token]` | String | no | The token to authenticate against Kubernetes |
+| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate |
+| `environment_scope` | String | no | The associated environment to the cluster **(PREMIUM)** |
+
+NOTE: **Note:**
+`name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added
+through the ["Add an existing Kubernetes Cluster"](../user/project/clusters/index.md#adding-an-existing-kubernetes-cluster) option or
+through the ["Add existing cluster to group"](#add-existing-cluster-to-group) endpoint.
+
+Example request:
+
+```bash
+curl --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/groups/26/clusters/24 \
+-H "Content-Type:application/json" \
+--request PUT --data '{"name":"new-cluster-name","domain":"new-domain.com","api_url":"https://new-api-url.com"}'
+```
+
+Example response:
+
+```json
+{
+ "id":24,
+ "name":"new-cluster-name",
+ "domain":"new-domain.com",
+ "created_at":"2019-01-03T21:53:40.610Z",
+ "provider_type":"user",
+ "platform_type":"kubernetes",
+ "environment_scope":"*",
+ "cluster_type":"group_type",
+ "user":
+ {
+ "id":1,
+ "name":"Administrator",
+ "username":"root",
+ "state":"active",
+ "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..",
+ "web_url":"https://gitlab.example.com/root"
+ },
+ "platform_kubernetes":
+ {
+ "api_url":"https://new-api-url.com",
+ "authorization_type":"rbac",
+ "ca_cert":null
+ },
+ "group":
+ {
+ "id":26,
+ "name":"group-with-clusters-api",
+ "web_url":"https://gitlab.example.com/group-with-clusters-api"
+ }
+}
+
+```
+
+## Delete group cluster
+
+Deletes an existing group cluster.
+
+```
+DELETE /groups/:id/clusters/:cluster_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+| `cluster_id` | integer | yes | The ID of the cluster |
+
+Example request:
+
+```bash
+curl --request DELETE --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/groups/26/clusters/23'
+```
diff --git a/doc/api/groups.md b/doc/api/groups.md
index d05e4b29fef..0d500f783aa 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -634,11 +634,13 @@ Parameters:
By default, groups only get 20 namespaces at a time because the API results are paginated.
To get more (up to 100), pass the following as an argument to the API call:
+
```
/groups?per_page=100
```
And to switch pages add:
+
```
/groups?per_page=100&page=2
```
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 23126a05b66..96a547551f1 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -357,7 +357,6 @@ GET /projects/:id/issues?confidential=true
| `updated_before` | datetime | no | Return issues updated on or before the given time |
| `confidential` | Boolean | no | Filter confidential or public issues. |
-
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues
```
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index 1add5f432ac..0e45ee1a583 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -409,10 +409,10 @@ Possible response status codes:
> - The use of `CI_JOB_TOKEN` in the artifacts download API was [introduced][ee-2346]
> in [GitLab Premium][ee] 9.5.
-Download the artifacts zipped archive from the given reference name and job,
-provided the job finished successfully. This is the same as
-[getting the job's artifacts](#get-job-artifacts), but by defining the job's
-name instead of its ID.
+Download the artifacts zipped archive from the latest successful pipeline for
+the given reference name and job, provided the job finished successfully. This
+is the same as [getting the job's artifacts](#get-job-artifacts), but by
+defining the job's name instead of its ID.
```
GET /projects/:id/jobs/artifacts/:ref_name/download?job=name
@@ -506,9 +506,9 @@ Possible response status codes:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23538) in GitLab 11.5.
-Download a single artifact file from a specific tag or branch from within the
-job's artifacts archive. The file is extracted from the archive and streamed to
-the client.
+Download a single artifact file for a specific job of the latest successful
+pipeline for the given reference name from within the job's artifacts archive.
+The file is extracted from the archive and streamed to the client.
```
GET /projects/:id/jobs/artifacts/:ref_name/raw/*artifact_path?job=name
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index de87e4a0aee..1ade46efb1c 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -44,7 +44,7 @@ Parameters:
| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead. |
| `author_id` | integer | no | Returns merge requests created by the given user `id`. Combine with `scope=all` or `scope=assigned_to_me` |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
-| `approver_ids` **(STARTER)** | Array[integer] | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
+| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch |
@@ -206,7 +206,7 @@ Parameters:
| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13060] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ |
-| `approver_ids` **(STARTER)** | Array[integer] | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
+| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch |
@@ -358,7 +358,7 @@ Parameters:
| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> |
| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ |
-| `approver_ids` **(STARTER)** | Array[integer] | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
+| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch |
@@ -1331,9 +1331,11 @@ If you don't have permissions to accept this merge request - you'll get a `401`
If the merge request is already merged or closed - you get `405` and error message 'Method Not Allowed'
In case the merge request is not set to be merged when the pipeline succeeds, you'll also get a `406` error.
+
```
PUT /projects/:id/merge_requests/:merge_request_iid/cancel_merge_when_pipeline_succeeds
```
+
Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
diff --git a/doc/api/protected_tags.md b/doc/api/protected_tags.md
index 3adca61a108..fb6fa040244 100644
--- a/doc/api/protected_tags.md
+++ b/doc/api/protected_tags.md
@@ -5,6 +5,7 @@
**Valid access levels**
Currently, these levels are recognized:
+
```
0 => No access
30 => Developer access
diff --git a/doc/api/releases/img/upcoming_release_v12_1.png b/doc/api/releases/img/upcoming_release_v12_1.png
new file mode 100644
index 00000000000..8bd8573ce84
--- /dev/null
+++ b/doc/api/releases/img/upcoming_release_v12_1.png
Binary files differ
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index e7f79a0d359..e74b35fd959 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -6,7 +6,7 @@
## List Releases
-Paginated list of Releases, sorted by `created_at`.
+Paginated list of Releases, sorted by `released_at`.
```
GET /projects/:id/releases
@@ -32,6 +32,7 @@ Example response:
"name":"Awesome app v0.2 beta",
"description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eEscape label and milestone titles to prevent XSS in GFM autocomplete. !2740\u003c/li\u003e\n\u003cli\u003ePrevent private snippets from being embeddable.\u003c/li\u003e\n\u003cli\u003eAdd subresources removal to member destroy service.\u003c/li\u003e\n\u003c/ul\u003e",
"created_at":"2019-01-03T01:56:19.539Z",
+ "released_at":"2019-01-03T01:56:19.539Z",
"author":{
"id":1,
"name":"Administrator",
@@ -98,6 +99,7 @@ Example response:
"name":"Awesome app v0.1 alpha",
"description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eRemove limit of 100 when searching repository code. !8671\u003c/li\u003e\n\u003cli\u003eShow error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\u003c/li\u003e\n\u003cli\u003eFix a bug where internal email pattern wasn't respected. !22516\u003c/li\u003e\n\u003c/ul\u003e",
"created_at":"2019-01-03T01:55:18.203Z",
+ "released_at":"2019-01-03T01:55:18.203Z",
"author":{
"id":1,
"name":"Administrator",
@@ -178,6 +180,7 @@ Example response:
"name":"Awesome app v0.1 alpha",
"description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eRemove limit of 100 when searching repository code. !8671\u003c/li\u003e\n\u003cli\u003eShow error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\u003c/li\u003e\n\u003cli\u003eFix a bug where internal email pattern wasn't respected. !22516\u003c/li\u003e\n\u003c/ul\u003e",
"created_at":"2019-01-03T01:55:18.203Z",
+ "released_at":"2019-01-03T01:55:18.203Z",
"author":{
"id":1,
"name":"Administrator",
@@ -247,6 +250,7 @@ POST /projects/:id/releases
| `assets:links`| array of hash | no | An array of assets links. |
| `assets:links:name`| string | no (if `assets:links` specified, it's required) | The name of the link. |
| `assets:links:url`| string | no (if `assets:links` specified, it's required) | The url of the link. |
+| `released_at` | datetime | no | The date when the release will be/was ready. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
Example request:
@@ -265,6 +269,7 @@ Example response:
"name":"New release",
"description_html":"\u003cp dir=\"auto\"\u003eSuper nice release\u003c/p\u003e",
"created_at":"2019-01-03T02:22:45.118Z",
+ "released_at":"2019-01-03T02:22:45.118Z",
"author":{
"id":1,
"name":"Administrator",
@@ -335,6 +340,7 @@ PUT /projects/:id/releases/:tag_name
| `tag_name` | string | yes | The tag where the release will be created from. |
| `name` | string | no | The release name. |
| `description` | string | no | The description of the release. You can use [markdown](../../user/markdown.md). |
+| `released_at` | datetime | no | The date when the release will be/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
Example request:
@@ -351,6 +357,7 @@ Example response:
"name":"new name",
"description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eRemove limit of 100 when searching repository code. !8671\u003c/li\u003e\n\u003cli\u003eShow error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\u003c/li\u003e\n\u003cli\u003eFix a bug where internal email pattern wasn't respected. !22516\u003c/li\u003e\n\u003c/ul\u003e",
"created_at":"2019-01-03T01:55:18.203Z",
+ "released_at":"2019-01-03T01:55:18.203Z",
"author":{
"id":1,
"name":"Administrator",
@@ -430,6 +437,7 @@ Example response:
"name":"new name",
"description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eRemove limit of 100 when searching repository code. !8671\u003c/li\u003e\n\u003cli\u003eShow error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\u003c/li\u003e\n\u003cli\u003eFix a bug where internal email pattern wasn't respected. !22516\u003c/li\u003e\n\u003c/ul\u003e",
"created_at":"2019-01-03T01:55:18.203Z",
+ "released_at":"2019-01-03T01:55:18.203Z",
"author":{
"id":1,
"name":"Administrator",
@@ -480,3 +488,11 @@ Example response:
}
}
```
+
+## Upcoming Releases
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/38105) in GitLab 12.1.
+
+A release with a `released_at` attribute set to a future date will be labeled an **Upcoming Release** in the UI:
+
+![Upcoming release](img/upcoming_release_v12_1.png)
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index ffae5c17310..4aff79c9c62 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -235,17 +235,17 @@ Example response:
```json
{
- "id": "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863",
- "short_id": "1a0b36b3",
- "title": "Initial commit",
- "created_at": "2014-02-27T08:03:18.000Z",
- "parent_ids": [],
- "message": "Initial commit\n",
- "author_name": "Dmitriy Zaporozhets",
- "author_email": "dmitriy.zaporozhets@gmail.com",
- "authored_date": "2014-02-27T08:03:18.000Z",
- "committer_name": "Dmitriy Zaporozhets",
- "committer_email": "dmitriy.zaporozhets@gmail.com",
- "committed_date": "2014-02-27T08:03:18.000Z"
+ "id": "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863",
+ "short_id": "1a0b36b3",
+ "title": "Initial commit",
+ "created_at": "2014-02-27T08:03:18.000Z",
+ "parent_ids": [],
+ "message": "Initial commit\n",
+ "author_name": "Dmitriy Zaporozhets",
+ "author_email": "dmitriy.zaporozhets@gmail.com",
+ "authored_date": "2014-02-27T08:03:18.000Z",
+ "committer_name": "Dmitriy Zaporozhets",
+ "committer_email": "dmitriy.zaporozhets@gmail.com",
+ "committed_date": "2014-02-27T08:03:18.000Z"
}
```
diff --git a/doc/api/repository_submodules.md b/doc/api/repository_submodules.md
index 2c44c4abc93..5a722a75cb9 100644
--- a/doc/api/repository_submodules.md
+++ b/doc/api/repository_submodules.md
@@ -43,7 +43,7 @@ Example response:
"ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"
],
"committed_date": "2018-09-20T09:26:24.000-07:00",
- "authored_date": "2018-09-20T09:26:24.000-07:00",
+ "authored_date": "2018-09-20T09:26:24.000-07:00",
"status": null
}
```
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index f8563e819db..1b8c23b8e2d 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -11,8 +11,6 @@ Read more about [system hooks](../system_hooks/system_hooks.md).
Get a list of all system hooks.
----
-
```
GET /hooks
```
@@ -44,8 +42,6 @@ Example response:
Add a new system hook.
----
-
```
POST /hooks
```
@@ -116,8 +112,6 @@ Example response:
Deletes a system hook.
----
-
```
DELETE /hooks/:id
```
@@ -130,4 +124,4 @@ Example request:
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/hooks/2
-``` \ No newline at end of file
+```
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 3177fec618f..af86ba961f4 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -141,6 +141,7 @@ Parameters:
"message": null
}
```
+
The message will be `null` when creating a lightweight tag otherwise
it will contain the annotation.
diff --git a/doc/api/users.md b/doc/api/users.md
index 213d1865aca..54641f4c862 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -357,9 +357,9 @@ Parameters:
- `admin` (optional) - User is admin - true or false (default)
- `can_create_group` (optional) - User can create groups - true or false
- `skip_confirmation` (optional) - Skip confirmation - true or false (default)
-- `external` (optional) - Flags the user as external - true or false(default)
+- `external` (optional) - Flags the user as external - true or false (default)
- `avatar` (optional) - Image file for user's avatar
-- `private_profile` (optional) - User's profile is private - true or false
+- `private_profile` (optional) - User's profile is private - true or false (default)
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user **(STARTER)**
- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user **(STARTER)**
@@ -392,11 +392,11 @@ Parameters:
- `admin` (optional) - User is admin - true or false (default)
- `can_create_group` (optional) - User can create groups - true or false
- `skip_reconfirmation` (optional) - Skip reconfirmation - true or false (default)
-- `external` (optional) - Flags the user as external - true or false(default)
+- `external` (optional) - Flags the user as external - true or false (default)
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user
- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user
- `avatar` (optional) - Image file for user's avatar
-- `private_profile` (optional) - User's profile is private - true or false
+- `private_profile` (optional) - User's profile is private - true or false (default)
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user **(STARTER)**
- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user **(STARTER)**
@@ -595,7 +595,7 @@ Example responses
## User counts
-Get the counts (same as in top right menu) of the currently signed in user.
+Get the counts (same as in top right menu) of the currently signed in user.
| Attribute | Type | Description |
| --------- | ---- | ----------- |
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 2d7fb323d79..83a9035c001 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -193,13 +193,14 @@ You can simply define an image that will be used for all jobs and a list of
services that you want to use during build time:
```yaml
-image: ruby:2.2
+default:
+ image: ruby:2.2
-services:
- - postgres:9.3
+ services:
+ - postgres:9.3
-before_script:
- - bundle install
+ before_script:
+ - bundle install
test:
script:
@@ -209,8 +210,9 @@ test:
It is also possible to define different images and services per job:
```yaml
-before_script:
- - bundle install
+default:
+ before_script:
+ - bundle install
test:2.1:
image: ruby:2.1
@@ -231,16 +233,53 @@ Or you can pass some [extended configuration options](#extended-docker-configura
for `image` and `services`:
```yaml
+default:
+ image:
+ name: ruby:2.2
+ entrypoint: ["/bin/bash"]
+
+ services:
+ - name: my-postgres:9.4
+ alias: db-postgres
+ entrypoint: ["/usr/local/bin/db-postgres"]
+ command: ["start"]
+
+ before_script:
+ - bundle install
+
+test:
+ script:
+ - bundle exec rake spec
+```
+
+## Passing environment variables to services
+
+You can also pass custom environment [variables](../variables/README.md)
+to fine tune your Docker `images` and `services` directly in the `.gitlab-ci.yml` file.
+For more information, see [custom environment variables](../variables/README.md#gitlab-ciyml-defined-variables)
+
+```yaml
+# The following variables will automatically be passed down to the Postgres container
+# as well as the Ruby container and available within each.
+variables:
+ HTTPS_PROXY: "https://10.1.1.1:8090"
+ HTTP_PROXY: "https://10.1.1.1:8090"
+ POSTGRES_DB: "my_custom_db"
+ POSTGRES_USER: "postgres"
+ POSTGRES_PASSWORD: "example"
+ PGDATA: "/var/lib/postgresql/data"
+ POSTGRES_INITDB_ARGS: "--encoding=UTF8 --data-checksums"
+
+services:
+- name: postgres:9.4
+ alias: db
+ entrypoint: ["docker-entrypoint.sh"]
+ command: ["postgres"]
+
image:
name: ruby:2.2
entrypoint: ["/bin/bash"]
-services:
-- name: my-postgres:9.4
- alias: db-postgres
- entrypoint: ["/usr/local/bin/db-postgres"]
- command: ["start"]
-
before_script:
- bundle install
diff --git a/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md b/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md
index 538843ab8dc..1d4c9221cf2 100644
--- a/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md
+++ b/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md
@@ -79,10 +79,10 @@ image: java:8
stages:
- build
- deploy
-
+
before_script:
- chmod +x mvnw
-
+
build:
stage: build
script: ./mvnw package
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
index d7308a3a5ec..1576efd5a7d 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -452,6 +452,7 @@ To start using Container Registry on our machine, we first need to login to the
```bash
docker login registry.gitlab.com
```
+
Then we can build and push our image to GitLab:
```bash
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index 0b9e9e93e55..1dd3049d53d 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -6,7 +6,7 @@ type: tutorial
This guide covers basic building instructions for PHP projects.
-Two testing scenarios are covered: using the Docker executor and
+Two testing scenarios are covered: using the Docker executor and
using the Shell executor.
## Test PHP projects using the Docker executor
diff --git a/doc/ci/git_submodules.md b/doc/ci/git_submodules.md
index 1354a26d6e2..cce33c7a6b4 100644
--- a/doc/ci/git_submodules.md
+++ b/doc/ci/git_submodules.md
@@ -69,12 +69,14 @@ correctly with your CI jobs:
1. Next, if you are using `gitlab-runner` v1.10+, you can set the
`GIT_SUBMODULE_STRATEGY` variable to either `normal` or `recursive` to tell
the runner to fetch your submodules before the job:
- ```yaml
- variables:
- GIT_SUBMODULE_STRATEGY: recursive
- ```
- See the [`.gitlab-ci.yml` reference](yaml/README.md#git-submodule-strategy)
- for more details about `GIT_SUBMODULE_STRATEGY`.
+
+ ```yaml
+ variables:
+ GIT_SUBMODULE_STRATEGY: recursive
+ ```
+
+ See the [`.gitlab-ci.yml` reference](yaml/README.md#git-submodule-strategy)
+ for more details about `GIT_SUBMODULE_STRATEGY`.
1. If you are using an older version of `gitlab-runner`, then use
`git submodule sync/update` in `before_script`:
diff --git a/doc/ci/interactive_web_terminal/index.md b/doc/ci/interactive_web_terminal/index.md
index 6c73cbbf8d7..58307660e51 100644
--- a/doc/ci/interactive_web_terminal/index.md
+++ b/doc/ci/interactive_web_terminal/index.md
@@ -8,7 +8,7 @@ type: reference
Interactive web terminals give the user access to a terminal in GitLab for
running one-off commands for their CI pipeline. Since this is giving the user
-shell access to the environment where [GitLab Runner](https://docs.gitlab.com/runner/)
+shell access to the environment where [GitLab Runner](https://docs.gitlab.com/runner/)
is deployed, some [security precautions](../../administration/integration/terminal.md#security) were
taken to protect the users.
@@ -62,4 +62,3 @@ close the terminal window.
## Interactive Web Terminals for the Web IDE **(ULTIMATE ONLY)**
Read the Web IDE docs to learn how to run [Interactive Terminals through the Web IDE](../../user/project/web_ide/index.md).
-
diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md
index 960346ac11a..b72dd6e920a 100644
--- a/doc/ci/services/postgres.md
+++ b/doc/ci/services/postgres.md
@@ -70,7 +70,7 @@ template1=# CREATE USER runner WITH PASSWORD '$password' CREATEDB;
```
*__Note:__ Notice that we created the user with the privilege to be able to
-create databases (`CREATEDB`). In the following steps we will create a database
+create databases (`CREATEDB`). In the following steps we will create a database
explicitly for that user but having that privilege can be useful if in your
testing framework you have tools that drop and create databases.*
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index c2ef58acf15..b1b193701c3 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -119,6 +119,35 @@ The following table lists available parameters for jobs:
NOTE: **Note:**
Parameters `types` and `type` are [deprecated](#deprecated-parameters).
+## Setting default parameters
+
+Some parameters can be set globally as the default for all jobs using the
+`default:` keyword. Default parameters can then be overridden by job-specific
+configuration.
+
+The following job parameters can be defined inside a `default:` block:
+
+- [`image`](#image)
+- [`services`](#services)
+- [`before_script`](#before_script-and-after_script)
+- [`after_script`](#before_script-and-after_script)
+- [`cache`](#cache)
+
+In the following example, the `ruby:2.5` image is set as the default for all
+jobs except the `rspec 2.6` job, which uses the `ruby:2.6` image:
+
+```yaml
+default:
+ image: ruby:2.5
+
+rspec:
+ script: bundle exec rspec
+
+rspec 2.6:
+ image: ruby:2.6
+ script: bundle exec rspec
+```
+
## Parameter details
The following are detailed explanations for parameters used to configure CI/CD pipelines.
@@ -239,8 +268,9 @@ It's possible to overwrite the globally defined `before_script` and `after_scrip
if you set it per-job:
```yaml
-before_script:
- - global before script
+default:
+ before_script:
+ - global before script
job:
before_script:
@@ -974,7 +1004,7 @@ review_app:
stop_review_app:
stage: deploy
variables:
- GIT_STRATEGY: none
+ GIT_STRATEGY: none
script: make delete-app
when: manual
environment:
@@ -2221,10 +2251,10 @@ spinach:
script: rake spinach
```
-It's also possible to use multiple parents for `extends`.
-The algorithm used for merge is "closest scope wins", so keys
-from the last member will always shadow anything defined on other levels.
-For example:
+In GitLab 12.0 and later, it's also possible to use multiple parents for
+`extends`. The algorithm used for merge is "closest scope wins", so
+keys from the last member will always shadow anything defined on other
+levels. For example:
```yaml
.only-important:
@@ -2550,18 +2580,39 @@ You can set it globally or per-job in the [`variables`](#variables) section.
The following parameters are deprecated.
-### `types`
+### Globally-defined `types`
CAUTION: **Deprecated:**
`types` is deprecated, and could be removed in a future release.
Use [`stages`](#stages) instead.
-### `type`
+### Job-defined `type`
CAUTION: **Deprecated:**
`type` is deprecated, and could be removed in one of the future releases.
Use [`stage`](#stage) instead.
+### Globally-defined `image`, `services`, `cache`, `before_script`, `after_script`
+
+Defining `image`, `services`, `cache`, `before_script`, and
+`after_script` globally is deprecated. Support could be removed
+from a future release.
+
+Use [`default:`](#setting-default-parameters) instead. For example:
+
+```yaml
+default:
+ image: ruby:2.5
+ services:
+ - docker:dind
+ cache:
+ paths: [vendor/]
+ before_script:
+ - bundle install --path vendor/
+ after_script:
+ - rm -rf tmp/
+```
+
## Custom build directories
> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1267) in Gitlab Runner 11.10
@@ -2644,7 +2695,7 @@ variables:
The value of `GIT_CLONE_PATH` is expanded once into
`$CI_BUILDS_DIR/go/src/namespace/project`, and results in failure
-because `$CI_BUILDS_DIR` is not expanded.
+because `$CI_BUILDS_DIR` is not expanded.
## Special YAML features
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index c83a0427c98..7569ccc04c1 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -424,12 +424,8 @@ Will generate a field called `mergeRequestSetWip` that
### Authorizing resources
-To authorize resources inside a mutation, we can include the
-`Gitlab::Graphql::Authorize::AuthorizeResource` concern in the
-mutation.
-
-This allows us to provide the required abilities on the mutation like
-this:
+To authorize resources inside a mutation, we first provide the required
+ abilities on the mutation like this:
```ruby
module Mutations
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index b645a72567c..091edb6ac40 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -147,7 +147,7 @@ Component statuses are linked to configuration documentation for each component.
| [Redis Exporter](#redis-exporter) | Prometheus endpoint with Redis metrics | [✅][redis-exporter-omnibus] | [✅][redis-exporter-charts] | [✅][redis-exporter-charts] | [✅](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
| [Postgres Exporter](#postgres-exporter) | Prometheus endpoint with PostgreSQL metrics | [✅][postgres-exporter-omnibus] | [✅][postgres-exporter-charts] | [✅][postgres-exporter-charts] | [✅](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
| [PgBouncer Exporter](#pgbouncer-exporter) | Prometheus endpoint with PgBouncer metrics | [⚙][pgbouncer-exporter-omnibus] | [❌][pgbouncer-exporter-charts] | [❌][pgbouncer-exporter-charts] | [✅](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
-| [GitLab Monitor](#gitlab-monitor) | Generates a variety of GitLab metrics | [✅][gitlab-monitor-omnibus] | [✅][gitab-monitor-charts] | [✅][gitab-monitor-charts] | [✅](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
+| [GitLab Monitor](#gitlab-monitor) | Generates a variety of GitLab metrics | [✅][gitlab-monitor-omnibus] | [✅][gitlab-monitor-charts] | [✅][gitlab-monitor-charts] | [✅](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
| [Node Exporter](#node-exporter) | Prometheus endpoint with system metrics | [✅][node-exporter-omnibus] | [❌][node-exporter-charts] | [❌][node-exporter-charts] | [✅](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
| [Mattermost](#mattermost) | Open-source Slack alternative | [⚙][mattermost-omnibus] | [⤓][mattermost-charts] | [⤓][mattermost-charts] | [⤓](../user/project/integrations/mattermost.md) | ❌ | ❌ | CE & EE |
| [MinIO](#minio) | Object storage service | [⤓][minio-omnibus] | [✅][minio-charts] | [✅][minio-charts] | [✅](https://about.gitlab.com/handbook/engineering/infrastructure/production-architecture/#storage-architecture) | ❌ | [⚙][minio-gdk] | CE & EE |
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index 3ed586f07e9..bd07a01e782 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -129,6 +129,7 @@ merge_request:
author:
type:
```
+
If you're working on the GitLab EE repository, the entry will be added to
`ee/changelogs/unreleased/` instead.
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index e60800f1ab7..35ce6b8cbe4 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -207,9 +207,9 @@ first time.
- Extract unrelated changes and refactorings into future merge requests/issues.
- Seek to understand the reviewer's perspective.
- Try to respond to every comment.
-- The merge request author resolves only the discussions they have fully
- addressed. If there's an open reply, an open discussion, a suggestion,
- a question, or anything else, the discussion should be left to be resolved
+- The merge request author resolves only the threads they have fully
+ addressed. If there's an open reply, an open thread, a suggestion,
+ a question, or anything else, the thread should be left to be resolved
by the reviewer.
- Push commits based on earlier rounds of feedback as isolated commits to the
branch. Do not squash until the branch is ready to merge. Reviewers should be
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 910f9f4bf7a..abe11b8d1a8 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -58,9 +58,9 @@ issue is labeled with a subject label corresponding to your expertise.
Subject labels are always all-lowercase.
-## Team labels
+## Team labels
-**Important**: Most of the team labels will be soon deprecated in favor of [Group labels](#group-labels).
+**Important**: Most of the team labels will be soon deprecated in favor of [Group labels](#group-labels).
Team labels specify what team is responsible for this issue.
Assigning a team label makes sure issues get the attention of the appropriate
@@ -98,7 +98,6 @@ indicate if an issue needs backend work, frontend work, or both.
Team labels are always capitalized so that they show up as the first label for
any issue.
-
## Stage labels
Stage labels specify which [DevOps stage][devops-stages] the issue belongs to.
@@ -141,43 +140,42 @@ Group labels specify which [groups][structure-groups] the issue belongs to.
The current group labels are:
-* ~"group::access"
-* ~"group::measure"
-* ~"group::source code"
-* ~"group::knowledge"
-* ~"group::editor"
-* ~"group::gitaly"
-* ~"group::gitter"
-* ~"group::team planning"
-* ~"group::enterprise planning"
-* ~"group::certify"
-* ~"group::ci and runner"
-* ~"group::testing"
-* ~"group::package"
-* ~"group::progressive delivery"
-* ~"group::release management"
-* ~"group::autodevops and kubernetes"
-* ~"group::serverless and paas"
-* ~"group::apm"
-* ~"group::health"
-* ~"group::static analysis"
-* ~"group::dynamic analysis"
-* ~"group::software composition analysis"
-* ~"group::runtime application security"
-* ~"group::threat management"
-* ~"group::application infrastructure security"
-* ~"group::activation"
-* ~"group::adoption"
-* ~"group::upsell"
-* ~"group::retention"
-* ~"group::fulfillment"
-* ~"group::telemetry"
-* ~"group::distribution"
-* ~"group::geo"
-* ~"group::memory"
-* ~"group::ecosystem"
+- ~"group::access"
+- ~"group::measure"
+- ~"group::source code"
+- ~"group::knowledge"
+- ~"group::editor"
+- ~"group::gitaly"
+- ~"group::gitter"
+- ~"group::team planning"
+- ~"group::enterprise planning"
+- ~"group::certify"
+- ~"group::ci and runner"
+- ~"group::testing"
+- ~"group::package"
+- ~"group::progressive delivery"
+- ~"group::release management"
+- ~"group::autodevops and kubernetes"
+- ~"group::serverless and paas"
+- ~"group::apm"
+- ~"group::health"
+- ~"group::static analysis"
+- ~"group::dynamic analysis"
+- ~"group::software composition analysis"
+- ~"group::runtime application security"
+- ~"group::threat management"
+- ~"group::application infrastructure security"
+- ~"group::activation"
+- ~"group::adoption"
+- ~"group::upsell"
+- ~"group::retention"
+- ~"group::fulfillment"
+- ~"group::telemetry"
+- ~"group::distribution"
+- ~"group::geo"
+- ~"group::memory"
+- ~"group::ecosystem"
-
These labels are [scoped labels](../../user/project/labels.md#scoped-labels-premium)
and thus are mutually exclusive.
@@ -192,15 +190,15 @@ can be applied to a single issue. You can find the groups listed in the
The current department labels are:
-* ~UX
-* ~Quality
+- ~UX
+- ~Quality
## Specialization labels
These labels narrow the [specialization](https://about.gitlab.com/company/team/structure/#specialist) on a unit of work.
-* ~frontend
-* ~backend
+- ~frontend
+- ~backend
## Release Scoping labels
@@ -248,10 +246,10 @@ There can be multiple facets of the impact. The below is a guideline.
If a bug seems to fall between two severity labels, assign it to the higher-severity label.
- Example(s) of ~S1
- - Data corruption/loss.
+ - Data corruption/loss.
- Security breach.
- Unable to create an issue or merge request.
- - Unable to add a comment or discussion to the issue or merge request.
+ - Unable to add a comment or thread to the issue or merge request.
- Example(s) of ~S2
- Cannot submit changes through the web IDE but the commandline works.
- A status widget on the merge request page is not working but information can be seen in the test pipeline page.
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 3f61ad7cb13..3325d3e074e 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -74,10 +74,10 @@ request is as follows:
can be found by running `grep css-class ./app -R`.
1. Be prepared to answer questions and incorporate feedback into your MR with new
commits. Once you have fully addressed a suggestion from a reviewer, click the
- "Resolve discussion" button beneath it to mark it resolved.
- 1. The merge request author resolves only the discussions they have fully addressed.
- If there's an open reply or discussion, a suggestion, a question, or anything else,
- the discussion should be left to be resolved by the reviewer.
+ "Resolve thread" button beneath it to mark it resolved.
+ 1. The merge request author resolves only the threads they have fully addressed.
+ If there's an open reply or thread, a suggestion, a question, or anything else,
+ the thread should be left to be resolved by the reviewer.
1. If your MR touches code that executes shell commands, reads or opens files, or
handles paths to files on disk, make sure it adheres to the
[shell command guidelines](../shell_commands.md)
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index cbdc0a3a174..36a2f47a55b 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -43,7 +43,7 @@ Meanwhile, anyone can contribute [documentation improvements](improvement-workfl
## Markdown and styles
-[GitLab docs](https://gitlab.com/gitlab-com/gitlab-docs) uses [GitLab Kramdown](https://gitlab.com/gitlab-org/gitlab_kramdown)
+[GitLab docs](https://gitlab.com/gitlab-org/gitlab-docs) uses [GitLab Kramdown](https://gitlab.com/gitlab-org/gitlab_kramdown)
as its markdown rendering engine. See the [GitLab Markdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/) for a complete Kramdown reference.
Adhere to the [Documentation Style Guide](styleguide.md). If a style standard is missing, you are welcome to suggest one via a merge request.
@@ -384,7 +384,7 @@ on how the left-side navigation menu is built and updated.
NOTE: **Note:**
To preview your changes to documentation locally, follow this
-[development guide](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/README.md#development-when-contributing-to-gitlab-documentation) or [these instructions for GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/gitlab_docs.md).
+[development guide](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/README.md#development-when-contributing-to-gitlab-documentation) or [these instructions for GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/gitlab_docs.md).
The live preview is currently enabled for the following projects:
@@ -408,7 +408,7 @@ You will need to push a branch to those repositories, it doesn't work for forks.
The `review-docs-deploy*` job will:
-1. Create a new branch in the [gitlab-docs](https://gitlab.com/gitlab-com/gitlab-docs)
+1. Create a new branch in the [gitlab-docs](https://gitlab.com/gitlab-org/gitlab-docs)
project named after the scheme: `$DOCS_GITLAB_REPO_SUFFIX-$CI_ENVIRONMENT_SLUG`,
where `DOCS_GITLAB_REPO_SUFFIX` is the suffix for each product, e.g, `ce` for
CE, etc.
@@ -464,7 +464,7 @@ If you want to know the in-depth details, here's what's really happening:
1. The preview URL is shown both at the job output and in the merge request
widget. You also get the link to the remote pipeline.
1. In the docs project, the pipeline is created and it
- [skips the test jobs](https://gitlab.com/gitlab-com/gitlab-docs/blob/8d5d5c750c602a835614b02f9db42ead1c4b2f5e/.gitlab-ci.yml#L50-55)
+ [skips the test jobs](https://gitlab.com/gitlab-org/gitlab-docs/blob/8d5d5c750c602a835614b02f9db42ead1c4b2f5e/.gitlab-ci.yml#L50-55)
to lower the build time.
1. Once the docs site is built, the HTML files are uploaded as artifacts.
1. A specific Runner tied only to the docs project, runs the Review App job
@@ -488,7 +488,7 @@ Currently, the following tests are in place:
that all cURL examples in API docs use the full switches. It's recommended
to [check locally](#previewing-the-changes-live) before pushing to GitLab by executing the command
`bundle exec nanoc check internal_links` on your local
- [`gitlab-docs`](https://gitlab.com/gitlab-com/gitlab-docs) directory.
+ [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs) directory.
1. [`ee_compat_check`](../automatic_ce_ee_merge.md#avoiding-ce-ee-merge-conflicts-beforehand) (runs on CE only):
When you submit a merge request to GitLab Community Edition (CE),
there is this additional job that runs against Enterprise Edition (EE)
diff --git a/doc/development/documentation/site_architecture/global_nav.md b/doc/development/documentation/site_architecture/global_nav.md
index 20eeebf444f..753a636a779 100644
--- a/doc/development/documentation/site_architecture/global_nav.md
+++ b/doc/development/documentation/site_architecture/global_nav.md
@@ -4,9 +4,9 @@ description: "Learn how GitLab docs' global navigation works and how to add new
# Global navigation
-> - [Introduced](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/362)
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/362)
in GitLab 11.6.
-> - [Updated](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/482) in GitLab 12.1.
+> - [Updated](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/482) in GitLab 12.1.
The global nav adds to the left sidebar the ability to
navigate and explore the contents of GitLab's documentation.
@@ -25,7 +25,7 @@ To add a new doc to the nav, first and foremost, check with the technical writin
Once you get their approval and their guidance in regards to the position on the nav,
read trhough this page to understand how it works, and submit a merge request to the
docs site, adding the doc you wish to include in the nav into the
-[global nav data file](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/content/_data/global-nav.yaml).
+[global nav data file](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/content/_data/global-nav.yaml).
Don't forget to ask a technical writer to review your changes before merging.
@@ -70,7 +70,7 @@ the data among the nav in containers properly [styled](#css-classes).
### Data file
-The [data file](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/content/_data/global-nav.yaml)
+The [data file](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/content/_data/global-nav.yaml)
is structured in three components: sections, categories, and docs.
#### Sections
@@ -248,9 +248,9 @@ Examples:
### Layout file (logic)
-The [layout](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/layouts/global_nav.html)
+The [layout](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/layouts/global_nav.html)
is fed by the [data file](#data-file), builds the global nav, and is rendered by the
-[default](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/layouts/default.html) layout.
+[default](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/layouts/default.html) layout.
There are three main considerations on the logic built for the nav:
diff --git a/doc/development/documentation/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md
index 6dd12b5efa7..1aef0ed855c 100644
--- a/doc/development/documentation/site_architecture/index.md
+++ b/doc/development/documentation/site_architecture/index.md
@@ -4,14 +4,14 @@ description: "Learn how GitLab's documentation website is architectured."
# Documentation site architecture
-Learn how we build and architecture [`gitlab-docs`](https://gitlab.com/gitlab-com/gitlab-docs)
+Learn how we build and architecture [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs)
and deploy it to <https://docs.gitlab.com>.
## Repository
While the source of the documentation content is stored in GitLab's respective product
repositories, the source that is used to build the documentation site _from that content_
-is located at <https://gitlab.com/gitlab-com/gitlab-docs>.
+is located at <https://gitlab.com/gitlab-org/gitlab-docs>.
The following diagram illustrates the relationship between the repositories
from where content is sourced, the `gitlab-docs` project, and the published output.
@@ -43,7 +43,7 @@ from where content is sourced, the `gitlab-docs` project, and the published outp
G --> L
```
-See the [README there](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/README.md)
+See the [README there](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/README.md)
for detailed information.
## Assets
@@ -76,7 +76,7 @@ read through the [global navigation](global_nav.md) doc.
The docs site is deployed to production with GitLab Pages, and previewed in
merge requests with Review Apps.
-The deployment aspects will be soon transferred from the [original document](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/README.md)
+The deployment aspects will be soon transferred from the [original document](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/README.md)
to this page.
<!--
diff --git a/doc/development/documentation/structure.md b/doc/development/documentation/structure.md
index fe676efa94d..025a946da0e 100644
--- a/doc/development/documentation/structure.md
+++ b/doc/development/documentation/structure.md
@@ -127,7 +127,7 @@ Notes:
## Help and feedback section
-The "help and feedback" section (introduced by [!319](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/319)) displayed at the end of each document
+The "help and feedback" section (introduced by [!319](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/319)) displayed at the end of each document
can be omitted from the doc by adding a key into the its frontmatter:
```yaml
@@ -142,7 +142,7 @@ you must check with a technical writer before doing so.
### Disqus
We also have integrated the docs site with Disqus (introduced by
-[!151](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/151)),
+[!151](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/151)),
allowing our users to post comments.
To omit only the comments from the feedback section, use the following
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index d9cea0614c3..1ca965f8ae9 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -340,7 +340,7 @@ For other punctuation rules, please refer to the
links shift too, which eventually leads to dead links. If you think it is
compelling to add numbers in headings, make sure to at least discuss it with
someone in the Merge Request.
-- [Avoid using symbols and special chars](https://gitlab.com/gitlab-com/gitlab-docs/issues/84)
+- [Avoid using symbols and special chars](https://gitlab.com/gitlab-org/gitlab-docs/issues/84)
in headers. Whenever possible, they should be plain and short text.
- Avoid adding things that show ephemeral statuses. For example, if a feature is
considered beta or experimental, put this info in a note, not in the heading.
@@ -488,7 +488,7 @@ You can link any up-to-date video that is useful to the GitLab user.
### Embed videos
-> [Introduced](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/472) in GitLab 12.1.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/472) in GitLab 12.1.
GitLab docs (docs.gitlab.com) support embedded videos.
@@ -801,7 +801,7 @@ GitLab.com Free, and all higher tiers.
### How it works
-Introduced by [!244](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/244),
+Introduced by [!244](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/244),
the special markup `**(STARTER)**` will generate a `span` element to trigger the
badges and tooltips (`<span class="badge-trigger starter">`). When the keyword
"only" is added, the corresponding GitLab.com badge will not be displayed.
diff --git a/doc/development/documentation/workflow.md b/doc/development/documentation/workflow.md
index 0abfe4b82a4..9f488fac7d0 100644
--- a/doc/development/documentation/workflow.md
+++ b/doc/development/documentation/workflow.md
@@ -6,5 +6,5 @@ description: Learn the processes for contributing to GitLab's documentation.
Documentation workflows at GitLab differ depending on the reason for the change:
-- [Documentation process for feature changes](feature-change-workflow.md) - The documentation is being created or updated as part of the development and release of a new or enhanced feature. This process involves the developer of the feature (who includes new/updated documentation files as part of the same merge request containing the feature's code) and also involves the product manager and technical writer who are listed for the feature's [DevOps stage](https://about.gitlab.com/handbook/product/categories/#devops-stages).
+- [Documentation process for feature changes](feature-change-workflow.md) - The documentation is being created or updated as part of the development and release of a new or enhanced feature. This process involves the developer of the feature (who includes new/updated documentation files as part of the same merge request containing the feature's code) and also involves the product manager and technical writer who are listed for the feature's [DevOps stage](https://about.gitlab.com/handbook/product/categories/#devops-stages).
- [Documentation improvement workflow](improvement-workflow.md) - All documentation additions not associated with a feature release. Documentation is being created or updated to improve accuracy, completeness, ease of use, or any reason other than a feature change. Anyone (and everyone) can contribute a merge request for this type of change at any time.
diff --git a/doc/development/fe_guide/design_patterns.md b/doc/development/fe_guide/design_patterns.md
index 0342d16a87c..2f372f783f5 100644
--- a/doc/development/fe_guide/design_patterns.md
+++ b/doc/development/fe_guide/design_patterns.md
@@ -53,6 +53,7 @@ When writing a class that needs to manipulate the DOM guarantee a container opti
This is useful when we need that class to be instantiated more than once in the same page.
Bad:
+
```javascript
class Foo {
constructor() {
@@ -63,6 +64,7 @@ new Foo();
```
Good:
+
```javascript
class Foo {
constructor(opts) {
@@ -72,6 +74,7 @@ class Foo {
new Foo({ container: '.my-element' });
```
+
You can find an example of the above in this [class][container-class-example];
[container-class-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/mini_pipeline_graph_dropdown.js
diff --git a/doc/development/fe_guide/droplab/droplab.md b/doc/development/fe_guide/droplab/droplab.md
index 2f8c79abde1..1c6d895b3ab 100644
--- a/doc/development/fe_guide/droplab/droplab.md
+++ b/doc/development/fe_guide/droplab/droplab.md
@@ -25,6 +25,7 @@ If you do not provide any arguments, it will globally query and instantiate all
<!-- ... -->
<ul>
```
+
```js
const droplab = new DropLab();
droplab.init();
@@ -45,6 +46,7 @@ You can add static list items.
<li>Static value 2</li>
<ul>
```
+
```js
const droplab = new DropLab();
droplab.init();
@@ -62,6 +64,7 @@ a non-global instance of DropLab using the `DropLab.prototype.init` method.
<!-- ... -->
<ul>
```
+
```js
const trigger = document.getElementById('trigger');
const list = document.getElementById('list');
@@ -79,6 +82,7 @@ You can also add hooks to an existing DropLab instance using `DropLab.prototype.
<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
<ul id="list" data-dropdown><!-- ... --><ul>
```
+
```js
const droplab = new DropLab();
@@ -109,6 +113,7 @@ for all `data-dynamic` dropdown lists tracked by that DropLab instance.
<li><a href="#" data-id="{{id}}">{{text}}</a></li>
</ul>
```
+
```js
const droplab = new DropLab();
@@ -131,6 +136,7 @@ the data as the second argument and the `id` of the trigger element as the first
<li><a href="#" data-id="{{id}}">{{text}}</a></li>
</ul>
```
+
```js
const droplab = new DropLab();
@@ -160,6 +166,7 @@ dropdown lists, one of which is dynamic.
</ul>
</div>
```
+
```js
const droplab = new DropLab();
@@ -216,6 +223,7 @@ Some plugins require configuration values, the config object can be passed as th
<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
<ul id="list" data-dropdown><!-- ... --><ul>
```
+
```js
const droplab = new DropLab();
diff --git a/doc/development/fe_guide/droplab/plugins/ajax.md b/doc/development/fe_guide/droplab/plugins/ajax.md
index b6a883ce6c4..4b76b207d88 100644
--- a/doc/development/fe_guide/droplab/plugins/ajax.md
+++ b/doc/development/fe_guide/droplab/plugins/ajax.md
@@ -17,18 +17,19 @@ Add the `Ajax` object to the plugins array of a `DropLab.prototype.init` or `Dro
<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
<ul id="list" data-dropdown><!-- ... --><ul>
```
+
```js
- const droplab = new DropLab();
+const droplab = new DropLab();
- const trigger = document.getElementById('trigger');
- const list = document.getElementById('list');
+const trigger = document.getElementById('trigger');
+const list = document.getElementById('list');
- droplab.addHook(trigger, list, [Ajax], {
- Ajax: {
- endpoint: '/some-endpoint',
- method: 'setData',
- },
- });
+droplab.addHook(trigger, list, [Ajax], {
+ Ajax: {
+ endpoint: '/some-endpoint',
+ method: 'setData',
+ },
+});
```
Optionally you can set `loadingTemplate` to a HTML string. This HTML string will
diff --git a/doc/development/fe_guide/droplab/plugins/filter.md b/doc/development/fe_guide/droplab/plugins/filter.md
index 1f188c64fe4..b867394a241 100644
--- a/doc/development/fe_guide/droplab/plugins/filter.md
+++ b/doc/development/fe_guide/droplab/plugins/filter.md
@@ -17,25 +17,26 @@ Add the `Filter` object to the plugins array of a `DropLab.prototype.init` or `D
<li><a href="#" data-id="{{id}}">{{text}}</a></li>
<ul>
```
+
```js
- const droplab = new DropLab();
-
- const trigger = document.getElementById('trigger');
- const list = document.getElementById('list');
-
- droplab.init(trigger, list, [Filter], {
- Filter: {
- template: 'text',
- },
- });
-
- droplab.addData('trigger', [{
- id: 0,
- text: 'Jacob',
- }, {
- id: 1,
- text: 'Jeff',
- }]);
+const droplab = new DropLab();
+
+const trigger = document.getElementById('trigger');
+const list = document.getElementById('list');
+
+droplab.init(trigger, list, [Filter], {
+ Filter: {
+ template: 'text',
+ },
+});
+
+droplab.addData('trigger', [{
+ id: 0,
+ text: 'Jacob',
+}, {
+ id: 1,
+ text: 'Jeff',
+}]);
```
Above, the input string will be compared against the `test` key of the passed data objects.
diff --git a/doc/development/fe_guide/droplab/plugins/input_setter.md b/doc/development/fe_guide/droplab/plugins/input_setter.md
index e4050213869..db492da478a 100644
--- a/doc/development/fe_guide/droplab/plugins/input_setter.md
+++ b/doc/development/fe_guide/droplab/plugins/input_setter.md
@@ -22,33 +22,34 @@ You can also set the `InputSetter` config to an array of objects, which will all
<li><a href="#" data-id="{{id}}">{{text}}</a></li>
<ul>
```
+
```js
- const droplab = new DropLab();
-
- const trigger = document.getElementById('trigger');
- const list = document.getElementById('list');
-
- const input = document.getElementById('input');
- const div = document.getElementById('div');
-
- droplab.init(trigger, list, [InputSetter], {
- InputSetter: [{
- input: input,
- valueAttribute: 'data-id',
- } {
- input: div,
- valueAttribute: 'data-id',
- inputAttribute: 'data-selected-id',
- }],
- });
-
- droplab.addData('trigger', [{
- id: 0,
- text: 'Jacob',
- }, {
- id: 1,
- text: 'Jeff',
- }]);
+const droplab = new DropLab();
+
+const trigger = document.getElementById('trigger');
+const list = document.getElementById('list');
+
+const input = document.getElementById('input');
+const div = document.getElementById('div');
+
+droplab.init(trigger, list, [InputSetter], {
+ InputSetter: [{
+ input: input,
+ valueAttribute: 'data-id',
+ } {
+ input: div,
+ valueAttribute: 'data-id',
+ inputAttribute: 'data-selected-id',
+ }],
+});
+
+droplab.addData('trigger', [{
+ id: 0,
+ text: 'Jacob',
+}, {
+ id: 1,
+ text: 'Jeff',
+}]);
```
Above, if the second list item was clicked, it would update the `#input` element
diff --git a/doc/development/fe_guide/event_tracking.md b/doc/development/fe_guide/event_tracking.md
index 6ab3fa4acf3..716f6ad7f92 100644
--- a/doc/development/fe_guide/event_tracking.md
+++ b/doc/development/fe_guide/event_tracking.md
@@ -47,7 +47,7 @@ There's a more convenient solution to this problem. When working with HAML templ
Below is an example of `data-track-*` attributes assigned to a button in HAML:
```ruby
-%button.btn{ data: { track_label: "create_from_template", track_property: "template_preview", track_event: "click_button", track_value: "my-template" } }
+%button.btn{ data: { track_label: "template_preview", track_property: "my-template", track_event: "click_button", track_value: "" } }
```
By calling `bindTrackableContainer('.my-container')`, click handlers get bound to all elements located in `.my-container` provided that they have the necessary `data-track-*` attributes assigned to them.
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index 36d5e4ab96b..6bf6113dd81 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -17,8 +17,6 @@ Working with our frontend assets requires Node (v8.10.0 or greater) and Yarn
For our currently-supported browsers, see our [requirements][requirements].
----
-
## Initiatives
Current high-level frontend goals are listed on [Frontend Epics](https://gitlab.com/groups/gitlab-org/-/epics?label_name%5B%5D=frontend).
@@ -77,8 +75,6 @@ How we use Snowplow to track custom events.
Read the [frontend's FAQ](frontend_faq.md) for common small pieces of helpful information.
----
-
## Style Guides
### [JavaScript Style Guide](style_guide_js.md)
@@ -91,20 +87,14 @@ changes.
Our SCSS conventions which are enforced through [scss-lint][scss-lint].
----
-
## [Performance](performance.md)
Best practices for monitoring and maximizing frontend performance.
----
-
## [Security](security.md)
Frontend security practices.
----
-
## [Accessibility](accessibility.md)
Our accessibility standards and resources.
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 6c7572352ec..421b7265613 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -34,6 +34,7 @@ new_feature
│ └── new_feature_store.js
├── index.js
```
+
_For consistency purposes, we recommend you to follow the same structure._
Let's look into each of them:
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index 5552d5d37b4..2ade59b76ed 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -237,24 +237,23 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
1. Create prometheus metrics:
```go
- var findAllTagsRequests = prometheus.NewCounterVec(
- prometheus.CounterOpts{
- Name: "gitaly_find_all_tags_requests_total",
- Help: "Counter of go vs ruby implementation of FindAllTags",
- },
- []string{"implementation"},
- )
+ var findAllTagsRequests = prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "gitaly_find_all_tags_requests_total",
+ Help: "Counter of go vs ruby implementation of FindAllTags",
+ },
+ []string{"implementation"},
)
func init() {
- prometheus.Register(findAllTagsRequests)
+ prometheus.Register(findAllTagsRequests)
}
if featureflag.IsEnabled(ctx, findAllTagsFeatureFlag) {
- findAllTagsRequests.WithLabelValues("go").Inc()
+ findAllTagsRequests.WithLabelValues("go").Inc()
// go implementation
} else {
- findAllTagsRequests.WithLabelValues("ruby").Inc()
+ findAllTagsRequests.WithLabelValues("ruby").Inc()
// ruby implementation
}
```
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index 35c5b155594..910d7296057 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -106,32 +106,31 @@ are very appreciative of the work done by translators and proofreaders!
1. Contribute translations to GitLab. See instructions for
[translating GitLab](translation.md).
- Translating GitLab is a community effort that requires team work and
- attention to detail. Proofreaders play an important role helping new
- contributors, and ensuring the consistency and quality of translations.
- Your conduct and contributions as a translator should reflect this before
- requesting to be a proofreader.
+ Translating GitLab is a community effort that requires team work and
+ attention to detail. Proofreaders play an important role helping new
+ contributors, and ensuring the consistency and quality of translations.
+ Your conduct and contributions as a translator should reflect this before
+ requesting to be a proofreader.
1. Request proofreader permissions by opening a merge request to add yourself
to the list of proofreaders.
- Open the [proofreader.md source file][proofreader-src] and click **Edit**.
+ Open the [proofreader.md source file][proofreader-src] and click **Edit**.
- Add your language in alphabetical order, and add yourself to the list
- including:
- - name
- - link to your GitLab profile
- - link to your CrowdIn profile
+ Add your language in alphabetical order, and add yourself to the list
+ including:
+ - name
+ - link to your GitLab profile
+ - link to your CrowdIn profile
- In the merge request description, please include links to any projects you
- have previously translated.
+ In the merge request description, please include links to any projects you
+ have previously translated.
1. Your request to become a proofreader will be considered on the merits of
your previous translations by [GitLab team members](https://about.gitlab.com/team/)
or [Core team members](https://about.gitlab.com/core-team/) who are fluent in
the language or current proofreaders.
- When a request is made for the first proofreader for a language and there are no [GitLab team members](https://about.gitlab.com/team/)
- or [Core team members](https://about.gitlab.com/core-team/) who speak the language, we will request links to previous translation work in other communities or projects.
-
+ or [Core team members](https://about.gitlab.com/core-team/) who speak the language, we will request links to previous translation work in other communities or projects.
[proofreader-src]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/i18n/proofreader.md
diff --git a/doc/development/integrations/jira_connect.md b/doc/development/integrations/jira_connect.md
index 9ba3b922fd8..e1350b02262 100644
--- a/doc/development/integrations/jira_connect.md
+++ b/doc/development/integrations/jira_connect.md
@@ -30,9 +30,11 @@ The following are required to install and test the app:
1. In the **From this URL** field, provide a link to the app descriptor. The host and port must point to your GitLab instance.
For example:
+
```
https://xxxx.serveo.net/-/jira_connect/app_descriptor.json
```
+
1. Click **Upload**.
If the install was successful, you should see the **GitLab for Jira** app under **Manage apps**.
diff --git a/doc/development/new_fe_guide/index.md b/doc/development/new_fe_guide/index.md
index 0e8f5486861..227d03bd86f 100644
--- a/doc/development/new_fe_guide/index.md
+++ b/doc/development/new_fe_guide/index.md
@@ -19,7 +19,6 @@ Learn about all the internal JavaScript modules that make up our frontend.
Style guides to keep our code consistent.
-
## [Tips](tips.md)
Tips from our frontend team to develop more efficiently and effectively.
diff --git a/doc/development/new_fe_guide/style/prettier.md b/doc/development/new_fe_guide/style/prettier.md
index 4495f38f262..5f44c640d76 100644
--- a/doc/development/new_fe_guide/style/prettier.md
+++ b/doc/development/new_fe_guide/style/prettier.md
@@ -4,7 +4,7 @@ Our code is automatically formatted with [Prettier](https://prettier.io) to foll
## Editor
-The easiest way to include prettier in your workflow is by setting up your preferred editor (all major editors are supported) accordingly. We suggest setting up prettier to run automatically when each file is saved. Find [here](https://prettier.io/docs/en/editors.html) the best way to set it up in your preferred editor.
+The easiest way to include prettier in your workflow is by setting up your preferred editor (all major editors are supported) accordingly. We suggest setting up prettier to run automatically when each file is saved. Find [here](https://prettier.io/docs/en/editors.html) the best way to set it up in your preferred editor.
Please take care that you only let Prettier format the same file types as the global Yarn script does (.js, .vue, and .scss). In VSCode by example you can easily exclude file formats in your settings file:
@@ -28,6 +28,7 @@ Updates all currently staged files (based on `git diff`) with Prettier and saves
```
yarn prettier-staged
```
+
Checks all currently staged files (based on `git diff`) with Prettier and log which files would need manual updating to the console.
```
diff --git a/doc/development/performance.md b/doc/development/performance.md
index c034f4a344b..8b569a677b6 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -246,6 +246,7 @@ irb(main):002:0> results.last.attributes.keys
irb(main):003:0> results.where(status: "passed").average(:time).to_s
=> "0.211340155844156"
```
+
These results can also be placed into a PostgreSQL database by setting the
`RSPEC_PROFILING_POSTGRES_URL` variable. This is used to profile the test suite
when running in the CI environment.
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 59eb3ecfd7e..2dc06ba10a5 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -148,7 +148,7 @@ Once you decided where to put [test environment orchestration scenarios] and
the [GitLab QA orchestrator README][gitlab-qa-readme], and [the already existing
instance-level scenarios][instance-level scenarios].
-Continued reading:
+Continued reading:
- [Quick Start Guide](quick_start_guide.md)
- [Style Guide](style_guide.md)
diff --git a/doc/development/testing_guide/end_to_end/quick_start_guide.md b/doc/development/testing_guide/end_to_end/quick_start_guide.md
index 064fb0e31dd..efcfd44bc22 100644
--- a/doc/development/testing_guide/end_to_end/quick_start_guide.md
+++ b/doc/development/testing_guide/end_to_end/quick_start_guide.md
@@ -222,7 +222,7 @@ As the pre-conditions for our test suite, the things that needs to happen before
- A project being created with an issue and labels already set;
- The issue page being opened with only one scoped label applied to it.
-> When running end-to-end tests as part of the GitLab's continuous integration process [a license is already set as an environment variable](https://gitlab.com/gitlab-org/gitlab-ee/blob/1a60d926740db10e3b5724713285780a4f470531/qa/qa/ee/strategy.rb#L20). For running tests locally you can set up such license by following the document [what tests can be run?](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md#supported-remote-grid-environment-variables), based on the [supported GitLab environment variables](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md#supported-gitlab-environment-variables).
+> When running end-to-end tests as part of the GitLab's continuous integration process [a license is already set as an environment variable](https://gitlab.com/gitlab-org/gitlab-ee/blob/1a60d926740db10e3b5724713285780a4f470531/qa/qa/ee/strategy.rb#L20). For running tests locally you can set up such license by following the document [what tests can be run?](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md), based on the [supported GitLab environment variables](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md#supported-gitlab-environment-variables).
#### Implementation
diff --git a/doc/development/testing_guide/end_to_end/style_guide.md b/doc/development/testing_guide/end_to_end/style_guide.md
index 0272e1810f2..6a888142575 100644
--- a/doc/development/testing_guide/end_to_end/style_guide.md
+++ b/doc/development/testing_guide/end_to_end/style_guide.md
@@ -63,17 +63,17 @@ We follow a simple formula roughly based on hungarian notation.
- `_checkbox`
- `_radio`
- `_content`
-
+
*Note: This list is a work in progress. This list will eventually be the end-all enumeration of all available types.
I.e., any element that does not end with something in this list is bad form.*
-
+
#### Examples
**Good**
```ruby
view '...' do
- element :edit_button
+ element :edit_button
element :notes_tab
element :squash_checkbox
element :username_field
@@ -84,16 +84,17 @@ end
**Bad**
```ruby
-view '...' do
+view '...' do
# `_confirmation` should be `_field`. what sort of confirmation? a checkbox confirmation? no real way to disambiguate.
# an appropriate replacement would be `element :password_confirmation_field`
element :password_confirmation
- # `clone_options` is too vague. If it's a dropdown menu, it should be `clone_dropdown`.
+ # `clone_options` is too vague. If it's a dropdown menu, it should be `clone_dropdown`.
# If it's a checkbox, it should be `clone_checkbox`
element :clone_options
-
+
# how is this url being displayed? is it a textbox? a simple span?
+ # If it is content on the page, it should be `ssh_clone_url_content`
element :ssh_clone_url
end
```
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 98df0b5ea7c..bb44cc595e9 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -501,17 +501,17 @@ The following are examples of tests that work for both Karma and Jest:
it('makes a request', () => {
const responseBody = getJSONFixture('some/fixture.json'); // loads spec/javascripts/fixtures/some/fixture.json
axiosMock.onGet(endpoint).reply(200, responseBody);
-
+
myButton.click();
-
+
// ...
});
it('uses some HTML element', () => {
loadFixtures('some/page.html'); // loads spec/javascripts/fixtures/some/page.html and adds it to the DOM
-
+
const element = document.getElementById('#my-id');
-
+
// ...
});
```
diff --git a/doc/development/testing_guide/index.md b/doc/development/testing_guide/index.md
index aadbea1a540..96e8c30a679 100644
--- a/doc/development/testing_guide/index.md
+++ b/doc/development/testing_guide/index.md
@@ -22,62 +22,44 @@ automated testing means, and what are its principles:
- [Five Factor Testing](https://www.devmynd.com/blog/five-factor-testing): Why do we need tests?
- [Principles of Automated Testing](http://www.lihaoyi.com/post/PrinciplesofAutomatedTesting.html): Levels of testing. Prioritize tests. Cost of tests.
----
-
## [Testing levels](testing_levels.md)
Learn about the different testing levels, and how to decide at what level your
changes should be tested.
----
-
## [Testing best practices](best_practices.md)
Everything you should know about how to write good tests: Test Design, RSpec, FactoryBot,
system tests, parameterized tests etc.
----
-
## [Frontend testing standards and style guidelines](frontend_testing.md)
Everything you should know about how to write good Frontend tests: Karma,
testing promises, stubbing etc.
----
-
## [Flaky tests](flaky_tests.md)
What are flaky tests, the different kind of flaky tests we encountered, and what
we do about them.
----
-
## [GitLab tests in the Continuous Integration (CI) context](ci.md)
How GitLab test suite is run in the CI context: setup, caches, artifacts,
parallelization, monitoring.
----
-
## [Review apps](review_apps.md)
How review apps are set up for GitLab CE/EE and how to use them.
----
-
## [Testing Rake tasks](testing_rake_tasks.md)
Everything you should know about how to test Rake tasks.
----
-
## [End-to-end tests](end_to_end/index.md)
Everything you should know about how to run end-to-end tests using
[GitLab QA][gitlab-qa] testing framework.
----
-
[Return to Development documentation](../README.md)
[RSpec]: https://github.com/rspec/rspec-rails#feature-specs
diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md
index b7e6844f43a..b8ebbbea9d4 100644
--- a/doc/gitlab-basics/command-line-commands.md
+++ b/doc/gitlab-basics/command-line-commands.md
@@ -139,6 +139,7 @@ pwd
```
clear
```
+
### Sample Git taskflow
If you are completely new to Git, looking through some [sample taskflows](https://rogerdudler.github.io/git-guide/) will help you understand best practices for using these commands as you work.
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 77caf6b5285..fed3b1ca595 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -227,7 +227,7 @@ Now, it's time to create the database:
choose a General Purpose (SSD) to reduce the costs). Read more about it at
[Storage for Amazon RDS](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Storage.html).
-1. The rest of the settings on this page request a DB isntance identifier, username
+1. The rest of the settings on this page request a DB instance identifier, username
and a master password. We've chosen to use `gitlab-db-ha`, `gitlab` and a
very secure password respectively. Keep these in hand for later.
1. Click **Next** to proceed to the advanced settings.
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index fff06254da7..20caac4cb74 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -42,7 +42,11 @@ use the packages that are available for your OS.
In order to improve elasticsearch indexing performance, GitLab has made available a [new indexer written in Go](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer).
This will replace the included Ruby indexer in the future but should be considered beta software for now, so there may be some bugs.
-If you would like to use it, please follow the instructions below.
+The Elasticsearch Go indexer is included in Omnibus for GitLab 11.8 and newer.
+
+To use the new Elasticsearch indexer included in Omnibus, check the box "Use the new repository indexer (beta)" when [enabling the Elasticsearch integration](#enabling-elasticsearch).
+
+If you would like to use the Elasticsearch Go indexer with a source installation or an older version of GitLab, please follow the instructions below.
### Installation
diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md
index b9dc2e123c5..36b4836e6b3 100644
--- a/doc/integration/oauth_provider.md
+++ b/doc/integration/oauth_provider.md
@@ -25,8 +25,6 @@ can be used for authentication to your GitLab instance
The 'GitLab Importer' feature is also using the OAuth protocol to give access
to repositories without sharing user credentials to your GitLab.com account.
----
-
GitLab supports two ways of adding a new OAuth2 application to an instance. You
can either add an application as a regular user or add it in the admin area.
What this means is that GitLab can actually have instance-wide and a user-wide
@@ -41,24 +39,18 @@ In order to add a new application via your profile, navigate to
![New OAuth application](img/oauth_provider_user_wide_applications.png)
----
-
In the application form, enter a **Name** (arbitrary), and make sure to set up
correctly the **Redirect URI** which is the URL where users will be sent after
they authorize with GitLab.
![New OAuth application form](img/oauth_provider_application_form.png)
----
-
When you hit **Submit** you will be provided with the application ID and
the application secret which you can then use with your application that
connects to GitLab.
![OAuth application ID and secret](img/oauth_provider_application_id_secret.png)
----
-
## OAuth applications in the admin area
To create an application that does not belong to a certain user, you can create
@@ -69,8 +61,6 @@ it from the admin area.
You're also able to mark an application as _trusted_ when creating it through the admin area. By doing that,
the user authorization step is automatically skipped for this application.
----
-
## Authorized applications
Every application you authorized to use your GitLab credentials will be shown
@@ -78,8 +68,6 @@ in the **Authorized applications** section under **Profile Settings > Applicatio
![Authorized_applications](img/oauth_provider_authorized_application.png)
----
-
GitLab's OAuth applications support scopes, which allow various actions that any given
application can perform such as `read_user` and `api`. There are many more scopes
available.
diff --git a/doc/migrate_ci_to_ce/README.md b/doc/migrate_ci_to_ce/README.md
index 7659b743311..51ff56b3541 100644
--- a/doc/migrate_ci_to_ce/README.md
+++ b/doc/migrate_ci_to_ce/README.md
@@ -181,7 +181,7 @@ sudo -u gitlab_ci -H bundle exec rake backup:show_secrets RAILS_ENV=production
### 2. SQL data and build traces
Create your final CI data export. If you are converting from MySQL to
- PostgreSQL, add ` MYSQL_TO_POSTGRESQL=1` to the end of the rake command. When
+PostgreSQL, add `MYSQL_TO_POSTGRESQL=1` to the end of the rake command. When
the command finishes it will print the path to your data export archive; you
will need this file later.
@@ -323,11 +323,15 @@ You should also make sure that you can:
### 2. Check Nginx configuration
- sudo nginx -t
+```sh
+sudo nginx -t
+```
### 3. Restart Nginx
- sudo /etc/init.d/nginx restart
+```sh
+sudo /etc/init.d/nginx restart
+```
### Restore from backup
@@ -352,11 +356,13 @@ The fix for this is to update to Omnibus 7.14 first and then update it to 8.0.
### Permission denied when accessing /var/opt/gitlab/gitlab-ci/builds
To fix that issue you have to change builds/ folder permission before doing final backup:
+
```
sudo chown -R gitlab-ci:gitlab-ci /var/opt/gitlab/gitlab-ci/builds
```
Then before executing `ci:migrate` you need to fix builds folder permission:
+
```
sudo chown git:git /var/opt/gitlab/gitlab-ci/builds
```
@@ -365,7 +371,7 @@ sudo chown git:git /var/opt/gitlab/gitlab-ci/builds
If you were migrating CI database from MySQL to PostgreSQL manually you can see errors during import about missing sequences:
-```sql
+```sql
ALTER SEQUENCE
ERROR: relation "ci_builds_id_seq" does not exist
ERROR: relation "ci_commits_id_seq" does not exist
diff --git a/doc/pages/getting_started_part_three.md b/doc/pages/getting_started_part_three.md
index b65247ff7b7..31a01a6c83b 100644
--- a/doc/pages/getting_started_part_three.md
+++ b/doc/pages/getting_started_part_three.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../user/project/pages/getting_started_part_three.md'
+redirect_to: '../user/project/pages/custom_domains_ssl_tls_certification/index.md'
---
-This document was moved to [another location](../user/project/pages/getting_started_part_three.md).
+This document was moved to [another location](../user/project/pages/custom_domains_ssl_tls_certification/index.md).
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 9b1a4105dc3..0d86df04367 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -315,8 +315,6 @@ if you see `411 Length Required` errors after attempting to upload, you may
need to downgrade the `aws_signature_version` value from the default value to
2 [due to this issue](https://github.com/fog/fog-aws/issues/428).
----
-
For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
@@ -428,8 +426,6 @@ For Omnibus GitLab packages:
1. [Reconfigure GitLab] for the changes to take effect
----
-
For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
@@ -490,8 +486,6 @@ For Omnibus GitLab packages:
1. [Reconfigure GitLab] for the changes to take effect.
----
-
For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
@@ -527,8 +521,6 @@ For Omnibus GitLab packages:
1. [Reconfigure GitLab] for the changes to take effect.
----
-
For installations from source:
1. Edit `/home/git/gitlab/config/gitlab.yml`:
@@ -580,8 +572,6 @@ There, add the following line to schedule the backup for everyday at 2 AM:
You may also want to set a limited lifetime for backups to prevent regular
backups using all your disk space.
----
-
For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
@@ -815,6 +805,7 @@ will have all your repositories, but not any other data.
## Troubleshooting
### Restoring database backup using omnibus packages outputs warnings
+
If you are using backup restore procedures you might encounter the following warnings:
```
@@ -843,7 +834,7 @@ including (but not restricted to):
- [CI/CD variables](../ci/variables/README.md)
- [Kubernetes / GCP integration](../user/project/clusters/index.md)
-- [Custom Pages domains](../user/project/pages/getting_started_part_three.md)
+- [Custom Pages domains](../user/project/pages/custom_domains_ssl_tls_certification/index.md)
- [Project error tracking](../user/project/operations/error_tracking.md)
- [Runner authentication](../ci/runners/README.md)
- [Project mirroring](../workflow/repository_mirroring.md)
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
index b59c06a24ea..8f65fab366e 100644
--- a/doc/raketasks/import.md
+++ b/doc/raketasks/import.md
@@ -100,7 +100,7 @@ the git repository's config file. This section is formatted as follows:
```
[gitlab]
- fullpath = gitlab-org/gitlab-ce
+ fullpath = gitlab-org/gitlab-ce
```
However, existing repositories were not migrated to include this path.
diff --git a/doc/security/information_exclusivity.md b/doc/security/information_exclusivity.md
index 62a20d3f257..749ccf924b5 100644
--- a/doc/security/information_exclusivity.md
+++ b/doc/security/information_exclusivity.md
@@ -1,6 +1,7 @@
---
type: concepts
---
+
# Information exclusivity
Git is a distributed version control system (DVCS). This means that everyone
diff --git a/doc/security/password_length_limits.md b/doc/security/password_length_limits.md
index d78293c75c6..9909ef4a8e4 100644
--- a/doc/security/password_length_limits.md
+++ b/doc/security/password_length_limits.md
@@ -1,19 +1,31 @@
---
type: reference, howto
---
+
# Custom password length limits
-If you want to enforce longer user passwords you can create an extra Devise
-initializer with the steps below.
+The user password length is set to a minimum of 8 characters by default.
+To change that for installations from source:
+
+1. Edit `devise_password_length.rb`:
+
+ ```sh
+ cd /home/git/gitlab
+ sudo -u git -H cp config/initializers/devise_password_length.rb.example config/initializers/devise_password_length.rb
+ sudo -u git -H editor config/initializers/devise_password_length.rb
+ ```
+
+1. Change the new password length limits:
+
+ ```ruby
+ config.password_length = 12..128
+ ```
-If you do not use the `devise_password_length.rb` initializer the password
-length is set to a minimum of 8 characters in `config/initializers/devise.rb`.
+ In this example, the minimum length is 12 characters, and the maximum length
+ is 128 characters.
-```bash
-cd /home/git/gitlab
-sudo -u git -H cp config/initializers/devise_password_length.rb.example config/initializers/devise_password_length.rb
-sudo -u git -H editor config/initializers/devise_password_length.rb # inspect and edit the new password length limits
-```
+1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
+ for the changes to take effect.
<!-- ## Troubleshooting
diff --git a/doc/security/rack_attack.md b/doc/security/rack_attack.md
index 8695b5d2194..1e5678ec47c 100644
--- a/doc/security/rack_attack.md
+++ b/doc/security/rack_attack.md
@@ -1,6 +1,7 @@
---
type: reference, howto
---
+
# Rack Attack
[Rack Attack](https://github.com/kickstarter/rack-attack), also known as Rack::Attack, is a Ruby gem
@@ -34,34 +35,34 @@ For more information on how to use these options check out
1. Open `/etc/gitlab/gitlab.rb` with your editor
1. Add the following:
- ```ruby
- gitlab_rails['rack_attack_git_basic_auth'] = {
- 'enabled' => true,
- 'ip_whitelist' => ["127.0.0.1"],
- 'maxretry' => 10, # Limit the number of Git HTTP authentication attempts per IP
- 'findtime' => 60, # Reset the auth attempt counter per IP after 60 seconds
- 'bantime' => 3600 # Ban an IP for one hour (3600s) after too many auth attempts
- }
- ```
+ ```ruby
+ gitlab_rails['rack_attack_git_basic_auth'] = {
+ 'enabled' => true,
+ 'ip_whitelist' => ["127.0.0.1"],
+ 'maxretry' => 10, # Limit the number of Git HTTP authentication attempts per IP
+ 'findtime' => 60, # Reset the auth attempt counter per IP after 60 seconds
+ 'bantime' => 3600 # Ban an IP for one hour (3600s) after too many auth attempts
+ }
+ ```
1. Reconfigure GitLab:
- ```
- sudo gitlab-ctl reconfigure
- ```
+ ```
+ sudo gitlab-ctl reconfigure
+ ```
The following settings can be configured:
- `enabled`: By default this is set to `false`. Set this to `true` to enable Rack Attack.
- `ip_whitelist`: Whitelist any IPs from being blocked. They must be formatted as strings within a Ruby array.
- CIDR notation is supported in GitLab v12.1 and up.
- For example, `["127.0.0.1", "127.0.0.2", "127.0.0.3", "192.168.0.1/24"]`.
+ CIDR notation is supported in GitLab v12.1 and up.
+ For example, `["127.0.0.1", "127.0.0.2", "127.0.0.3", "192.168.0.1/24"]`.
- `maxretry`: The maximum amount of times a request can be made in the
- specified time.
+ specified time.
- `findtime`: The maximum amount of time that failed requests can count against an IP
- before it's blacklisted (in seconds).
+ before it's blacklisted (in seconds).
- `bantime`: The total amount of time that a blacklisted IP will be blocked (in
- seconds).
+ seconds).
**Installations from source**
@@ -71,18 +72,18 @@ taken in order to enable protection for your GitLab instance:
1. In `config/application.rb` find and uncomment the following line:
- ```ruby
- config.middleware.use Rack::Attack
- ```
+ ```ruby
+ config.middleware.use Rack::Attack
+ ```
1. Copy `config/initializers/rack_attack.rb.example` to `config/initializers/rack_attack.rb`
1. Open `config/initializers/rack_attack.rb`, review the
`paths_to_be_protected`, and add any other path you need protecting
1. Restart GitLab:
- ```sh
- sudo service gitlab restart
- ```
+ ```sh
+ sudo service gitlab restart
+ ```
If you want more restrictive/relaxed throttle rules, edit
`config/initializers/rack_attack.rb` and change the `limit` or `period` values.
@@ -98,28 +99,28 @@ In case you want to remove a blocked IP, follow these steps:
1. Find the IPs that have been blocked in the production log:
- ```sh
- grep "Rack_Attack" /var/log/gitlab/gitlab-rails/auth.log
- ```
+ ```sh
+ grep "Rack_Attack" /var/log/gitlab/gitlab-rails/auth.log
+ ```
1. Since the blacklist is stored in Redis, you need to open up `redis-cli`:
- ```sh
- /opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket
- ```
+ ```sh
+ /opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket
+ ```
1. You can remove the block using the following syntax, replacing `<ip>` with
the actual IP that is blacklisted:
- ```
- del cache:gitlab:rack::attack:allow2ban:ban:<ip>
- ```
+ ```
+ del cache:gitlab:rack::attack:allow2ban:ban:<ip>
+ ```
1. Confirm that the key with the IP no longer shows up:
- ```
- keys *rack::attack*
- ```
+ ```
+ keys *rack::attack*
+ ```
1. Optionally, add the IP to the whitelist to prevent it from being blacklisted
again (see [settings](#settings)).
@@ -136,8 +137,8 @@ the load balancer. In that case, you will need to:
1. Whitelist the load balancer's IP address(es) in the Rack Attack [settings](#settings).
1. Reconfigure GitLab:
- ```
- sudo gitlab-ctl reconfigure
- ```
+ ```
+ sudo gitlab-ctl reconfigure
+ ```
1. [Remove the block via Redis.](#remove-blocked-ips-from-rack-attack-via-redis)
diff --git a/doc/security/reset_root_password.md b/doc/security/reset_root_password.md
index a58d70f0ff2..6a6c5262179 100644
--- a/doc/security/reset_root_password.md
+++ b/doc/security/reset_root_password.md
@@ -1,6 +1,7 @@
---
type: howto
---
+
# How to reset your root password
To reset your root password, first log into your server with root privileges.
diff --git a/doc/security/ssh_keys_restrictions.md b/doc/security/ssh_keys_restrictions.md
index ae4cc44519e..4c60daf77f4 100644
--- a/doc/security/ssh_keys_restrictions.md
+++ b/doc/security/ssh_keys_restrictions.md
@@ -1,6 +1,7 @@
---
type: reference, howto
---
+
# Restrict allowed SSH key technologies and minimum length
`ssh-keygen` allows users to create RSA keys with as few as 768 bits, which
diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md
index 49dadd5abc2..b08d9ffa26e 100644
--- a/doc/security/two_factor_authentication.md
+++ b/doc/security/two_factor_authentication.md
@@ -1,6 +1,7 @@
---
type: howto
---
+
# Enforce Two-factor Authentication (2FA)
Two-factor Authentication (2FA) provides an additional level of security to your
@@ -48,11 +49,11 @@ need to be administrator or owner of the group.
The following are important notes about 2FA:
- Projects belonging to a 2FA-enabled group that
- [is shared](../user/project/members/share_project_with_groups.md)
+ [is shared](../user/project/members/share_project_with_groups.md)
with a 2FA-disabled group will *not* require members of the 2FA-disabled group to use
- 2FA for the project. For example, if project *P* belongs to 2FA-enabled group *A* and
+ 2FA for the project. For example, if project *P* belongs to 2FA-enabled group *A* and
is shared with 2FA-disabled group *B*, members of group *B* can access project *P*
- without 2FA. To ensure this scenario doesn't occur,
+ without 2FA. To ensure this scenario doesn't occur,
[prevent sharing of projects](../user/group/index.md#share-with-group-lock)
for the 2FA-enabled group.
- If you add additional members to a project within a group or subgroup that has
diff --git a/doc/security/unlock_user.md b/doc/security/unlock_user.md
index 75cf754e197..d34826c853c 100644
--- a/doc/security/unlock_user.md
+++ b/doc/security/unlock_user.md
@@ -1,38 +1,45 @@
---
type: howto
---
-# How to unlock a locked user
-To unlock a locked user, first log into your server with root privileges.
+# How to unlock a locked user from the command line
-Start a Ruby on Rails console with this command:
+After six failed login attempts a user gets in a locked state.
+To unlock a locked user:
-```bash
-gitlab-rails console production
-```
+1. SSH into your GitLab server.
+1. Start a Ruby on Rails console:
-Wait until the console has loaded.
+ ```sh
+ ## For Omnibus GitLab
+ sudo gitlab-rails console production
-There are multiple ways to find your user. You can search for email or username.
+ ## For installations from source
+ sudo -u git -H bundle exec rails console RAILS_ENV=production
+ ```
-```bash
-user = User.where(id: 1).first
-```
+1. Find the user to unlock. You can search by email or ID.
-or
+ ```ruby
+ user = User.find_by(email: 'admin@local.host')
+ ```
-```bash
-user = User.find_by(email: 'admin@local.host')
-```
+ or
-Unlock the user:
+ ```ruby
+ user = User.where(id: 1).first
+ ```
-```bash
-user.unlock_access!
-```
+1. Unlock the user:
-Exit the console, the user should now be able to log in again.
+ ```ruby
+ user.unlock_access!
+ ```
+
+1. Exit the console with <kbd>Ctrl</kbd>+<kbd>d</kbd>
+
+The user should now be able to log in.
<!-- ## Troubleshooting
diff --git a/doc/security/user_email_confirmation.md b/doc/security/user_email_confirmation.md
index f0af0a7ac6a..7ba50acbb06 100644
--- a/doc/security/user_email_confirmation.md
+++ b/doc/security/user_email_confirmation.md
@@ -1,6 +1,7 @@
---
type: howto
---
+
# User email confirmation at sign-up
GitLab can be configured to require confirmation of a user's email address when
diff --git a/doc/security/user_file_uploads.md b/doc/security/user_file_uploads.md
index 00a2607b607..9fc8f7ec985 100644
--- a/doc/security/user_file_uploads.md
+++ b/doc/security/user_file_uploads.md
@@ -1,6 +1,7 @@
---
type: reference
---
+
# User File Uploads
Images that are attached to issues, merge requests, or comments
@@ -12,7 +13,7 @@ image contains sensitive information.
Authentication is not enabled because images must be visible in the body of
notification emails, which are often read from email clients that are not
authenticated with GitLab, such as Outlook, Apple Mail, or the Mail app on your
-mobile device.
+mobile device.
>**Note:**
Non-image attachments do require authentication to be viewed.
diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md
index d4fa088cb15..1194234a295 100644
--- a/doc/security/webhooks.md
+++ b/doc/security/webhooks.md
@@ -1,6 +1,7 @@
---
type: concepts, reference, howto
---
+
# Webhooks and insecure internal web services
If you have non-GitLab web services running on your GitLab server or within its
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index dbd9bcee935..e18f49de3f0 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -64,13 +64,13 @@ Following [best practices](https://linux-audit.com/using-ed25519-openssh-keys-in
you should always favor [ED25519](https://ed25519.cr.yp.to/) SSH keys, since they
are more secure and have better performance over the other types.
-ED25519 SSH keys were introduced in OpenSSH 6.5,
-so any modern OS should include the option to create them.
-If for any reason your OS or the GitLab instance you interact with doesn't
+ED25519 SSH keys were introduced in OpenSSH 6.5,
+so any modern OS should include the option to create them.
+If for any reason your OS or the GitLab instance you interact with doesn't
support ED25519, you can fallback to RSA.
NOTE: **Note:**
-Omnibus does not ship with OpenSSH, so it uses the version on your GitLab server. If using
+Omnibus does not ship with OpenSSH, so it uses the version on your GitLab server. If using
Omnibus, ensure the version of OpenSSH installed is version 6.5 or newer if you want to use ED25519 SSH keys.
### RSA SSH keys
@@ -107,18 +107,18 @@ To create a new SSH key pair:
1. Open a terminal on Linux or macOS, or Git Bash / WSL on Windows.
1. Generate a new ED25519 SSH key pair:
- ```bash
- ssh-keygen -t ed25519 -C "email@example.com"
- ```
+ ```bash
+ ssh-keygen -t ed25519 -C "email@example.com"
+ ```
- Or, if you want to use RSA:
+ Or, if you want to use RSA:
- ```bash
- ssh-keygen -o -t rsa -b 4096 -C "email@example.com"
- ```
+ ```bash
+ ssh-keygen -o -t rsa -b 4096 -C "email@example.com"
+ ```
- The `-C` flag adds a comment in the key in case you have multiple of them
- and want to tell which is which. It is optional.
+ The `-C` flag adds a comment in the key in case you have multiple of them
+ and want to tell which is which. It is optional.
1. Next, you will be prompted to input a file path to save your SSH key pair to.
If you don't already have an SSH key pair and aren't generating a [deploy key](#deploy-keys),
@@ -126,21 +126,21 @@ To create a new SSH key pair:
<kbd>Enter</kbd>. Using the suggested path will normally allow your SSH client
to automatically use the SSH key pair with no additional configuration.
- If you already have an SSH key pair with the suggested file path, you will need
- to input a new file path and [declare what host](#working-with-non-default-ssh-key-pair-paths)
- this SSH key pair will be used for in your `~/.ssh/config` file.
+ If you already have an SSH key pair with the suggested file path, you will need
+ to input a new file path and [declare what host](#working-with-non-default-ssh-key-pair-paths)
+ this SSH key pair will be used for in your `~/.ssh/config` file.
1. Once the path is decided, you will be prompted to input a password to
secure your new SSH key pair. It's a best practice to use a password,
but it's not required and you can skip creating it by pressing
<kbd>Enter</kbd> twice.
- If, in any case, you want to add or change the password of your SSH key pair,
- you can use the `-p` flag:
+ If, in any case, you want to add or change the password of your SSH key pair,
+ you can use the `-p` flag:
- ```
- ssh-keygen -p -o -f <keyname>
- ```
+ ```
+ ssh-keygen -p -o -f <keyname>
+ ```
Now, it's time to add the newly created public key to your GitLab account.
@@ -149,41 +149,40 @@ Now, it's time to add the newly created public key to your GitLab account.
1. Copy your **public** SSH key to the clipboard by using one of the commands below
depending on your Operating System:
- **macOS:**
+ **macOS:**
- ```bash
- pbcopy < ~/.ssh/id_ed25519.pub
- ```
+ ```bash
+ pbcopy < ~/.ssh/id_ed25519.pub
+ ```
- **WSL / GNU/Linux (requires the xclip package):**
+ **WSL / GNU/Linux (requires the xclip package):**
- ```bash
- xclip -sel clip < ~/.ssh/id_ed25519.pub
- ```
+ ```bash
+ xclip -sel clip < ~/.ssh/id_ed25519.pub
+ ```
- **Git Bash on Windows:**
+ **Git Bash on Windows:**
- ```bash
- cat ~/.ssh/id_ed25519.pub | clip
- ```
+ ```bash
+ cat ~/.ssh/id_ed25519.pub | clip
+ ```
- You can also open the key in a graphical editor and copy it from there,
- but be careful not to accidentally change anything.
+ You can also open the key in a graphical editor and copy it from there,
+ but be careful not to accidentally change anything.
- NOTE: **Note:**
- If you opted to create an RSA key, the name might differ.
+ NOTE: **Note:**
+ If you opted to create an RSA key, the name might differ.
1. Add your **public** SSH key to your GitLab account by:
1. Clicking your avatar in the upper right corner and selecting **Settings**.
1. Navigating to **SSH Keys** and pasting your **public** key in the **Key** field. If you:
-
- Created the key with a comment, this will appear in the **Title** field.
- Created the key without a comment, give your key an identifiable title like _Work Laptop_ or _Home Workstation_.
1. Click the **Add key** button.
- NOTE: **Note:**
- If you manually copied your public SSH key make sure you copied the entire
- key starting with `ssh-ed25519` (or `ssh-rsa`) and ending with your email.
+ NOTE: **Note:**
+ If you manually copied your public SSH key make sure you copied the entire
+ key starting with `ssh-ed25519` (or `ssh-rsa`) and ending with your email.
## Testing that everything is set up correctly
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index a46f7d30892..e8bd35fba5c 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -330,6 +330,7 @@ If the user is blocked via LDAP, `state` will be `ldap_blocked`.
"user_id": 41
}
```
+
**Group Member Removed:**
```json
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 503ad784a77..f9ad952aaad 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -109,10 +109,10 @@ To make full use of Auto DevOps, you will need:
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.
- 1. **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)
- Helm chart.
+ 1. **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)
+ Helm chart.
1. **Prometheus** (needed for Auto Monitoring) - To enable Auto Monitoring, you
will need Prometheus installed somewhere (inside or outside your cluster) and
configured to scrape your Kubernetes cluster. To get response metrics
@@ -168,7 +168,6 @@ From GitLab 11.8, `KUBE_INGRESS_BASE_DOMAIN` replaces `AUTO_DEVOPS_DOMAIN`.
Support for `AUTO_DEVOPS_DOMAIN` was [removed in GitLab
12.0](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959).
-
## Using multiple Kubernetes clusters **(PREMIUM)**
When using Auto DevOps, you may want to deploy different environments to
@@ -202,7 +201,7 @@ To add a different cluster for each environment:
1. Navigate to your project's **Operations > Kubernetes** and create the Kubernetes clusters
with their respective environment scope as described from the table above.
- ![Auto DevOps multiple clusters](img/autodevops_multiple_clusters.png)
+ ![Auto DevOps multiple clusters](img/autodevops_multiple_clusters.png)
1. After the clusters are created, navigate to each one and install Helm Tiller
and Ingress. Wait for the Ingress IP address to be assigned.
@@ -223,7 +222,7 @@ full use of Auto DevOps are available. If this is your fist time, we recommend y
[quick start guide](quick_start_guide.md).
GitLab.com users can enable/disable Auto DevOps at the project-level only. Self-managed users
-can enable/disable Auto DevOps at either the project-level or instance-level.
+can enable/disable Auto DevOps at the project-level, group-level or instance-level.
### Enabling/disabling Auto DevOps at the instance-level (Administrators only)
diff --git a/doc/university/training/topics/env_setup.md b/doc/university/training/topics/env_setup.md
index 305f5ecb1fb..92d2613c5d2 100644
--- a/doc/university/training/topics/env_setup.md
+++ b/doc/university/training/topics/env_setup.md
@@ -14,9 +14,11 @@ comments: false
- If it's not installed, it will prompt you to install it.
- **Linux**
+
```bash
sudo yum install git-all
```
+
```bash
sudo apt-get install git-all
```
diff --git a/doc/user/admin_area/geo_nodes.md b/doc/user/admin_area/geo_nodes.md
index 9e7057f93d4..39753fd885e 100644
--- a/doc/user/admin_area/geo_nodes.md
+++ b/doc/user/admin_area/geo_nodes.md
@@ -64,8 +64,8 @@ Internal URL defaults to External URL, but you can customize it under
CAUTION: **Warning:**
We recommend using an HTTPS connection while configuring the Geo nodes. To avoid
breaking communication between **primary** and **secondary** nodes when using
-HTTPS, customize your Internal URL to point to a Load Balancer with TLS
-termination.
+HTTPS, customize your Internal URL to point to a load balancer with TLS
+terminated at the load balancer.
## Multiple secondary nodes behind a load balancer
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index 9968b7349dc..7fbb4d84cfc 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -41,7 +41,7 @@ These settings can be found within:
- The path `/admin/application_settings`.
The first push of a new project, including LFS objects, will be checked for size
-and **will** be rejected if the sum of their sizes exceeds the maximum allowed
+and **will** be rejected if the sum of their sizes exceeds the maximum allowed
repository size.
**Note:** The repository size limit includes repository files and LFS, and does not include artifacts.
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index ebbb2472752..e56acac527f 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -94,7 +94,7 @@ a group in the **Usage Quotas** page available to the group page settings list.
![Group pipelines quota](img/group_pipelines_quota.png)
-## Extra Shared Runners pipeline minutes quota **[FREE ONLY]**
+## Extra Shared Runners pipeline minutes quota **(FREE ONLY)**
If you're using GitLab.com, you can purchase additional CI minutes so your
pipelines will not be blocked after you have used all your CI minutes from your
@@ -164,3 +164,23 @@ questions that you know someone might ask.
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
but commented out to help encourage others to add to it in the future. -->
+
+## Required pipeline configuration **(PREMIUM ONLY)**
+
+GitLab administrators can force a pipeline configuration to run on every
+pipeline.
+
+The configuration applies to all pipelines for a GitLab instance and is
+sourced from:
+
+- The [instance template repository](instance_template_repository.md).
+- GitLab-supplied configuration.
+
+To set required pipeline configuration:
+
+1. Go to **Admin area > Settings > CI/CD**.
+1. Expand the **Required pipeline configuration** section.
+1. Select the required configuration from the provided dropdown.
+1. Click **Save changes**.
+
+![Required pipeline](img/admin_required_pipeline.png)
diff --git a/doc/user/admin_area/settings/img/admin_required_pipeline.png b/doc/user/admin_area/settings/img/admin_required_pipeline.png
new file mode 100644
index 00000000000..58488674d51
--- /dev/null
+++ b/doc/user/admin_area/settings/img/admin_required_pipeline.png
Binary files differ
diff --git a/doc/user/admin_area/settings/sign_up_restrictions.md b/doc/user/admin_area/settings/sign_up_restrictions.md
index cebf36c7ec1..d77e91156f8 100644
--- a/doc/user/admin_area/settings/sign_up_restrictions.md
+++ b/doc/user/admin_area/settings/sign_up_restrictions.md
@@ -4,8 +4,8 @@ type: reference
# Sign-up restrictions
-You can block email addresses of specific domains, or whitelist only some
-specific domains via the **Application Settings** in the Admin area.
+By implementing sign-up restrictions, you can blacklist or whitelist email addresses
+belonging to specific domains.
>**Note**: These restrictions are only applied during sign-up. An admin is
able to add a user through the admin panel with a disallowed domain. Also
@@ -24,17 +24,21 @@ domains list.
> [Introduced][ce-5259] in GitLab 8.10.
With this feature enabled, you can block email addresses of a specific domain
-from creating an account on your GitLab server. This is particularly useful to
-prevent spam. Disposable email addresses are usually used by malicious users to
-create dummy accounts and spam issues.
+from creating an account on your GitLab server. This is particularly useful to prevent spam. Disposable email addresses are usually used by malicious users to create dummy accounts and spam issues.
## Settings
-This feature can be activated via the **Application Settings** in the Admin area,
-and you have the option of entering the list manually, or uploading a file with
-the list.
+To access this feature:
-Both whitelist and blacklist accept wildcards, so for example, you can use
+1. Navigate to the **Settings > General** in the Admin area.
+1. Expand the **Sign-up restrictions** section.
+
+For the:
+
+- Blacklist, you can enter the list manually, or upload a `.txt` file with it.
+- Whitelist you must enter the list manually.
+
+Both the whitelist and blacklist accept wildcards. For example, you can use
`*.company.com` to accept every `company.com` subdomain, or `*.io` to block all
domains ending in `.io`. Domains should be separated by a whitespace,
semicolon, comma, or a new line.
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 696446599c8..da75684a3fe 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -10,7 +10,7 @@ images (or more precisely the containers) for known vulnerabilities by using
[Clair](https://github.com/coreos/clair) and [clair-scanner](https://github.com/arminc/clair-scanner),
two open source tools for Vulnerability Static Analysis for containers.
-You can take advantage of Container Scanning by either [including the CI job](#including-the-provided-template) in
+You can take advantage of Container Scanning by either [including the CI job](#configuration) in
your existing `.gitlab-ci.yml` file or by implicitly using
[Auto Container Scanning](../../../topics/autodevops/index.md#auto-container-scanning-ultimate)
that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
@@ -55,32 +55,16 @@ To enable Container Scanning in your pipeline, you need:
[predefined environment variables](../../../ci/variables/predefined_variables.md)
document.
-## Configuring Container Scanning
+## Configuration
-To enable Container Scanning in your project, define a job in your
-`.gitlab-ci.yml` file that generates the
-[Container Scanning report artifact](../../../ci/yaml/README.md#artifactsreportscontainer_scanning-ultimate).
+For GitLab 11.9 and later, to enable Container Scanning, you must
+[include](../../../ci/yaml/README.md#includetemplate) the
+[`Container-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml)
+that's provided as a part of your GitLab installation.
+For GitLab versions earlier than 11.9, you can copy and use the job as defined
+in that template.
-This can be done in two ways:
-
-- For GitLab 11.9 and later, including the provided
- `Container-Scanning.gitlab-ci.yml` template (recommended).
-- Manually specifying the job definition. Not recommended unless using GitLab
- 11.8 and earlier.
-
-### Including the provided template
-
-NOTE: **Note:**
-The CI/CD Container Scanning template is supported on GitLab 11.9 and later versions.
-For earlier versions, use the [manual job definition](#manual-job-definition-for-gitlab-115-and-later).
-
-A CI/CD [Container Scanning template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml)
-with the default Container Scanning job definition is provided as a part of your GitLab
-installation that you can [include](../../../ci/yaml/README.md#includetemplate)
-in your `.gitlab-ci.yml` file.
-
-To enable Container Scanning using the provided template, add the following to
-your `.gitlab-ci.yml` file:
+Add the following to your `.gitlab-ci.yml` file:
```yaml
include:
@@ -89,12 +73,12 @@ include:
The included template will:
-- Create a `container_scanning` job in your CI/CD pipeline.
-- Pull the already built Docker image from your project's
- [Container Registry](../../project/container_registry.md) (see [requirements](#requirements))
- and scan it for possible vulnerabilities.
+1. Create a `container_scanning` job in your CI/CD pipeline.
+1. Pull the already built Docker image from your project's
+ [Container Registry](../../project/container_registry.md) (see [requirements](#requirements))
+ and scan it for possible vulnerabilities.
-The report will be saved as a
+The results will be saved as a
[Container Scanning report artifact](../../../ci/yaml/README.md#artifactsreportscontainer_scanning-ultimate)
that you can later download and analyze.
Due to implementation limitations, we always take the latest Container Scanning
@@ -106,95 +90,6 @@ 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).
-### Manual job definition for GitLab 11.5 and later
-
-CAUTION: **Caution:**
-The job definition shown below is supported on GitLab 11.5 and later versions.
-However, if you're using GitLab 11.9+, it's recommended to use
-[the provided Container Scanning template](#including-the-provided-template).
-
-For GitLab 11.5 and GitLab Runner 11.5 and later, the following `container_scanning`
-job can be added:
-
-```yaml
-container_scanning:
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- ## Define two new variables based on GitLab's CI/CD predefined variables
- ## https://docs.gitlab.com/ee/ci/variables/README.html#predefined-environment-variables
- CI_APPLICATION_REPOSITORY: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG
- CI_APPLICATION_TAG: $CI_COMMIT_SHA
- CLAIR_LOCAL_SCAN_VERSION: v2.0.8_fe9b059d930314b54c78f75afe265955faf4fdc1
- allow_failure: true
- services:
- - docker:stable-dind
- script:
- - docker run -d --name db arminc/clair-db:latest
- - docker run -p 6060:6060 --link db:postgres -d --name clair --restart on-failure arminc/clair-local-scan:${CLAIR_LOCAL_SCAN_VERSION}
- - apk add -U wget ca-certificates
- - docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG}
- - wget https://github.com/arminc/clair-scanner/releases/download/v8/clair-scanner_linux_amd64
- - mv clair-scanner_linux_amd64 clair-scanner
- - chmod +x clair-scanner
- - touch clair-whitelist.yml
- - while( ! wget -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; done
- - retries=0
- - echo "Waiting for clair daemon to start"
- - while( ! wget -T 10 -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
- - ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
- artifacts:
- reports:
- container_scanning: gl-container-scanning-report.json
-```
-
-### Manual job definition for GitLab 11.4 and earlier (deprecated)
-
-CAUTION: **Deprecated:**
-Before GitLab 11.5, the Container Scanning job and artifact had to be named specifically
-to automatically extract report data and show it in the merge request widget.
-While these old job definitions are still maintained, they have been deprecated
-and may be removed in the next major release, GitLab 12.0. You are strongly
-advised to update your current `.gitlab-ci.yml` configuration to reflect that change.
-
-For GitLab 11.4 and earlier, the Container Scanning job should look like:
-
-```yaml
-container_scanning:
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- ## Define two new variables based on GitLab's CI/CD predefined variables
- ## https://docs.gitlab.com/ee/ci/variables/README.html#predefined-environment-variables
- CI_APPLICATION_REPOSITORY: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG
- CI_APPLICATION_TAG: $CI_COMMIT_SHA
- CLAIR_LOCAL_SCAN_VERSION: v2.0.8_fe9b059d930314b54c78f75afe265955faf4fdc1
- allow_failure: true
- services:
- - docker:stable-dind
- script:
- - docker run -d --name db arminc/clair-db:latest
- - docker run -p 6060:6060 --link db:postgres -d --name clair --restart on-failure arminc/clair-local-scan:${CLAIR_LOCAL_SCAN_VERSION}
- - apk add -U wget ca-certificates
- - docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG}
- - wget https://github.com/arminc/clair-scanner/releases/download/v8/clair-scanner_linux_amd64
- - mv clair-scanner_linux_amd64 clair-scanner
- - chmod +x clair-scanner
- - touch clair-whitelist.yml
- - while( ! wget -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; done
- - retries=0
- - echo "Waiting for clair daemon to start"
- - while( ! wget -T 10 -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
- - ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
- artifacts:
- paths: [gl-container-scanning-report.json]
-```
-
-Alternatively, the job name could be `sast:container`
-and the artifact name could be `gl-sast-container-report.json`.
-These names have been deprecated with GitLab 11.0
-and may be removed in the next major release, GitLab 12.0.
-
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 936703cce32..a0a917c5ebd 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -14,7 +14,7 @@ Dynamic Application Security Testing (DAST) comes into place.
If you are using [GitLab CI/CD](../../../ci/README.md), you can analyze your running web application(s)
for known vulnerabilities using Dynamic Application Security Testing (DAST).
-You can take advantage of DAST by either [including the CI job](#configuring-dast) in
+You can take advantage of DAST by either [including the CI job](#configuration) in
your existing `.gitlab-ci.yml` file or by implicitly using
[Auto DAST](../../../topics/autodevops/index.md#auto-dast-ultimate)
that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
@@ -51,30 +51,16 @@ applications while you are developing and testing your applications.
To run a DAST job, you need GitLab Runner with the
[`docker` executor](https://docs.gitlab.com/runner/executors/docker.html).
-## Configuring DAST
+## Configuration
-To enable DAST in your project, define a job in your `.gitlab-ci.yml` file that generates the
-[DAST report artifact](../../../ci/yaml/README.md#artifactsreportsdast-ultimate).
+For GitLab 11.9 and later, to enable DAST, you must
+[include](../../../ci/yaml/README.md#includetemplate) the
+[`DAST.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml)
+that's provided as a part of your GitLab installation.
+For GitLab versions earlier than 11.9, you can copy and use the job as defined
+in that template.
-This can be done in two ways:
-
-- For GitLab 11.9 and later, including the provided `DAST.gitlab-ci.yml` template (recommended).
-- Manually specifying the job definition. Not recommended unless using GitLab
- 11.8 and earlier.
-
-### Including the provided template
-
-NOTE: **Note:**
-The CI/CD DAST template is supported on GitLab 11.9 and later versions.
-For earlier versions, use the [manual job definition](#manual-job-definition-for-gitlab-115-and-later).
-
-A CI/CD [DAST template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml)
-with the default DAST job definition is provided as a part of your GitLab
-installation which you can [include](../../../ci/yaml/README.md#includetemplate)
-in your `.gitlab-ci.yml` file.
-
-To enable DAST using the provided template, add the following to your `.gitlab-ci.yml`
-file:
+Add the following to your `.gitlab-ci.yml` file:
```yaml
include:
@@ -84,22 +70,22 @@ variables:
DAST_WEBSITE: https://example.com
```
+There are two ways to define the URL to be scanned by DAST:
+
+- Set the `DAST_WEBSITE` [variable](../../../ci/yaml/README.md#variables).
+- Add it in an `environment_url.txt` file at the root of your project.
+
The included template will create a `dast` job in your CI/CD pipeline and scan
your project's source code for possible vulnerabilities.
-The report will be saved as a
+The results will be saved as a
[DAST report artifact](../../../ci/yaml/README.md#artifactsreportsdast-ultimate)
that you can later download and analyze. Due to implementation limitations we
always take the latest DAST artifact available. Behind the scenes, the
[GitLab DAST Docker image](https://gitlab.com/gitlab-org/security-products/dast)
is used to run the tests on the specified URL and scan it for possible vulnerabilities.
-There are two ways to define the URL to be scanned by DAST:
-
-- Set the `DAST_WEBSITE` [variable](../../../ci/yaml/README.md#variables).
-- Add it in an `environment_url.txt` file at the root of your project.
-
-#### Authenticated scan
+### Authenticated scan
It's also possible to authenticate the user before performing the DAST checks:
@@ -117,12 +103,12 @@ variables:
DAST_AUTH_EXCLUDE_URLS: http://example.com/sign-out,http://example.com/sign-out-2 # optional, URLs to skip during the authenticated scan; comma-separated, no spaces in between
```
-The report will be saved as a
+The results will be saved as a
[DAST report artifact](../../../ci/yaml/README.md#artifactsreportsdast-ultimate)
that you can later download and analyze.
Due to implementation limitations, we always take the latest DAST artifact available.
-#### Full scan
+### Full scan
DAST can be configured to perform [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan), which
includes both passive and active scanning against the same target website:
@@ -135,7 +121,7 @@ variables:
DAST_FULL_SCAN_ENABLED: "true"
```
-#### Customizing the DAST settings
+### Customizing the DAST settings
The DAST settings can be changed through environment variables by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
@@ -155,7 +141,7 @@ variables:
Because the template is [evaluated before](../../../ci/yaml/README.md#include) the pipeline
configuration, the last mention of the variable will take precedence.
-#### Overriding the DAST template
+### Overriding the DAST template
If you want to override the job definition (for example, change properties like
`variables` or `dependencies`), you need to declare a `dast` job after the
@@ -176,79 +162,6 @@ As the DAST job belongs to a separate `dast` stage that runs after all
[default stages](../../../ci/yaml/README.md#stages),
don't forget to add `stage: dast` when you override the template job definition.
-### Manual job definition for GitLab 11.5 and later
-
-For GitLab 11.5 and GitLab Runner 11.5 and later, the following `dast`
-job can be added:
-
-```yaml
-dast:
- image: registry.gitlab.com/gitlab-org/security-products/zaproxy
- variables:
- website: "https://example.com"
- allow_failure: true
- script:
- - mkdir /zap/wrk/
- - /zap/zap-baseline.py -J gl-dast-report.json -t $website || true
- - cp /zap/wrk/gl-dast-report.json .
- artifacts:
- reports:
- dast: gl-dast-report.json
-```
-
-Where the `website` variable holds the URL to run the tests against.
-
-For an authenticated scan, use the following definition:
-
-```yaml
-dast:
- image: registry.gitlab.com/gitlab-org/security-products/zaproxy
- variables:
- website: "https://example.com"
- login_url: "https://example.com/sign-in"
- username: "john.doe@example.com"
- password: "john-doe-password"
- allow_failure: true
- script:
- - mkdir /zap/wrk/
- - /zap/zap-baseline.py -J gl-dast-report.json -t $website
- --auth-url $login_url
- --auth-username $username
- --auth-password $password || true
- - cp /zap/wrk/gl-dast-report.json .
- artifacts:
- reports:
- dast: gl-dast-report.json
-```
-
-See the [zaproxy documentation](https://gitlab.com/gitlab-org/security-products/zaproxy)
-to learn more about the authentication settings.
-
-### Manual job definition for GitLab 11.4 and earlier (deprecated)
-
-CAUTION: **Caution:**
-Before GitLab 11.5, DAST job and artifact had to be named specifically
-to automatically extract report data and show it in the merge request widget.
-While these old job definitions are still maintained they have been deprecated
-and may be removed in next major release, GitLab 12.0. You are strongly advised
-to update your current `.gitlab-ci.yml` configuration to reflect that change.
-
-For GitLab 11.4 and earlier, the job should look like:
-
-```yaml
-dast:
- image: registry.gitlab.com/gitlab-org/security-products/zaproxy
- variables:
- website: "https://example.com"
- allow_failure: true
- script:
- - mkdir /zap/wrk/
- - /zap/zap-baseline.py -J gl-dast-report.json -t $website || true
- - cp /zap/wrk/gl-dast-report.json .
- artifacts:
- paths: [gl-dast-report.json]
-```
-
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 2fe8a6f9029..0dd0fd3f136 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -8,7 +8,7 @@ in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.7.
If you are using [GitLab CI/CD](../../../ci/README.md), you can analyze your dependencies for known
vulnerabilities using Dependency Scanning.
-You can take advantage of Dependency Scanning by either [including the CI job](#including-the-provided-template)
+You can take advantage of Dependency Scanning by either [including the CI job](#configuration)
in your existing `.gitlab-ci.yml` file or by implicitly using
[Auto Dependency Scanning](../../../topics/autodevops/index.md#auto-dependency-scanning-ultimate)
that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
@@ -74,31 +74,16 @@ The Gemnasium client does **NOT** send the exact package versions your project r
You can disable the remote checks by [using](#customizing-the-dependency-scanning-settings)
the `DS_DISABLE_REMOTE_CHECKS` environment variable and setting it to `true`.
-## Configuring Dependency Scanning
+## Configuration
-To enable Dependency Scanning in your project, define a job in your `.gitlab-ci.yml`
-file that generates the
-[Dependency Scanning report artifact](../../../ci/yaml/README.md#artifactsreportsdependency_scanning-ultimate).
+For GitLab 11.9 and later, to enable Dependency Scanning, you must
+[include](../../../ci/yaml/README.md#includetemplate) the
+[`Dependency-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml)
+that's provided as a part of your GitLab installation.
+For GitLab versions earlier than 11.9, you can copy and use the job as defined
+that template.
-This can be done in two ways:
-
-- For GitLab 11.9 and later, including the provided `Dependency-Scanning.gitlab-ci.yml` template (recommended).
-- Manually specifying the job definition. Not recommended unless using GitLab
- 11.8 and earlier.
-
-### Including the provided template
-
-NOTE: **Note:**
-The CI/CD Dependency Scanning template is supported on GitLab 11.9 and later versions.
-For earlier versions, use the [manual job definition](#manual-job-definition-for-gitlab-115-and-later).
-
-A CI/CD [Dependency Scanning template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml)
-with the default Dependency Scanning job definition is provided as a part of your GitLab
-installation which you can [include](../../../ci/yaml/README.md#includetemplate)
-in your `.gitlab-ci.yml` file.
-
-To enable Dependency Scanning using the provided template, add the following to
-your `.gitlab-ci.yml` file:
+Add the following to your `.gitlab-ci.yml` file:
```yaml
include:
@@ -108,12 +93,12 @@ include:
The included template will create a `dependency_scanning` job in your CI/CD
pipeline and scan your project's source code for possible vulnerabilities.
-The report will be saved as a
+The results will be saved as a
[Dependency Scanning report artifact](../../../ci/yaml/README.md#artifactsreportsdependency_scanning-ultimate)
that you can later download and analyze. Due to implementation limitations, we
always take the latest Dependency Scanning artifact available.
-#### Customizing the Dependency Scanning settings
+### Customizing the Dependency Scanning settings
The Dependency Scanning settings can be changed through [environment variables](#available-variables) by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
@@ -131,7 +116,7 @@ variables:
Because template is [evaluated before](../../../ci/yaml/README.md#include) the pipeline
configuration, the last mention of the variable will take precedence.
-#### Overriding the Dependency Scanning template
+### Overriding the Dependency Scanning template
If you want to override the job definition (for example, change properties like
`variables` or `dependencies`), you need to declare a `dependency_scanning` job
@@ -146,7 +131,7 @@ dependency_scanning:
CI_DEBUG_TRACE: "true"
```
-#### Available variables
+### Available variables
Dependency Scanning can be [configured](#customizing-the-dependency-scanning-settings)
using environment variables.
@@ -156,6 +141,7 @@ using environment variables.
| `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_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). |
@@ -164,82 +150,6 @@ using environment variables.
| `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`. |
-### Manual job definition for GitLab 11.5 and later
-
-For GitLab 11.5 and GitLab Runner 11.5 and later, the following `dependency_scanning`
-job can be added:
-
-```yaml
-dependency_scanning:
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- allow_failure: true
- services:
- - docker:stable-dind
- script:
- - export DS_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- - |
- docker run \
- --env DS_ANALYZER_IMAGES \
- --env DS_ANALYZER_IMAGE_PREFIX \
- --env DS_ANALYZER_IMAGE_TAG \
- --env DS_DEFAULT_ANALYZERS \
- --env DEP_SCAN_DISABLE_REMOTE_CHECKS \
- --env DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
- --env DS_PULL_ANALYZER_IMAGE_TIMEOUT \
- --env DS_RUN_ANALYZER_TIMEOUT \
- --volume "$PWD:/code" \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$DS_VERSION" /code
- dependencies: []
- artifacts:
- reports:
- dependency_scanning: gl-dependency-scanning-report.json
-```
-
-You can supply many other [settings variables](#available-variables)
-via `docker run --env` to customize your job execution.
-
-### Manual job definition for GitLab 11.4 and earlier (deprecated)
-
-CAUTION: **Caution:**
-Before GitLab 11.5, the Dependency Scanning job and artifact had to be named specifically
-to automatically extract the report data and show it in the merge request widget.
-While these old job definitions are still maintained, they have been deprecated
-and may be removed in the next major release, GitLab 12.0. You are strongly advised
-to update your current `.gitlab-ci.yml` configuration to reflect that change.
-
-For GitLab 11.4 and earlier, the job should look like:
-
-```yaml
-dependency_scanning:
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- allow_failure: true
- services:
- - docker:stable-dind
- script:
- - export DS_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- - |
- docker run \
- --env DS_ANALYZER_IMAGES \
- --env DS_ANALYZER_IMAGE_PREFIX \
- --env DS_ANALYZER_IMAGE_TAG \
- --env DS_DEFAULT_ANALYZERS \
- --env DS_EXCLUDED_PATHS \
- --env DEP_SCAN_DISABLE_REMOTE_CHECKS \
- --env DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
- --env DS_PULL_ANALYZER_IMAGE_TIMEOUT \
- --env DS_RUN_ANALYZER_TIMEOUT \
- --volume "$PWD:/code" \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$DS_VERSION" /code
- artifacts:
- paths: [gl-dependency-scanning-report.json]
-```
-
## Reports JSON format
CAUTION: **Caution:**
diff --git a/doc/user/application_security/license_management/index.md b/doc/user/application_security/license_management/index.md
index 8eb231f8359..b0eb753938b 100644
--- a/doc/user/application_security/license_management/index.md
+++ b/doc/user/application_security/license_management/index.md
@@ -8,7 +8,7 @@ in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
If you are using [GitLab CI/CD](../../../ci/README.md), you can search your project dependencies for their licenses
using License Management.
-You can take advantage of License Management by either [including the job](#configuring-license-management)
+You can take advantage of License Management by either [including the job](#configuration)
in your existing `.gitlab-ci.yml` file or by implicitly using
[Auto License Management](../../../topics/autodevops/index.md#auto-license-management-ultimate)
that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
@@ -65,33 +65,16 @@ The following languages and package managers are supported.
To run a License Management scanning job, you need GitLab Runner with the
[`docker` executor](https://docs.gitlab.com/runner/executors/docker.html).
-## Configuring License Management
+## Configuration
-To enable License Management in your project, define a job in your `.gitlab-ci.yml`
-file that generates the [License Management report artifact](../../../ci/yaml/README.md#artifactsreportslicense_management-ultimate).
+For GitLab 11.9 and later, to enable License Management, you must
+[include](../../../ci/yaml/README.md#includetemplate) the
+[`License-Management.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/License-Management.gitlab-ci.yml)
+that's provided as a part of your GitLab installation.
+For GitLab versions earlier than 11.9, you can copy and use the job as defined
+that template.
-This can be done in two ways:
-
-- For GitLab 11.9 and later, including the provided `License-Management.gitlab-ci.yml` template (recommended).
-- Manually specifying the job definition. Not recommended unless using GitLab
- 11.8 and earlier.
-
-The License Management settings can be changed through environment variables by using the
-[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`. These variables are documented in the [License Management documentation](https://gitlab.com/gitlab-org/security-products/license-management#settings).
-
-### Including the provided template
-
-NOTE: **Note:**
-The CI/CD License Management template is supported on GitLab 11.9 and later versions.
-For earlier versions, use the [manual job definition](#manual-job-definition-for-gitlab-115-and-later).
-
-A CI/CD [License Management template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/License-Management.gitlab-ci.yml)
-with the default License Management job definition is provided as a part of your GitLab
-installation which you can [include](../../../ci/yaml/README.md#includetemplate)
-in your `.gitlab-ci.yml` file.
-
-To enable License Management using the provided template, add the following to
-your `.gitlab-ci.yml` file:
+Add the following to your `.gitlab-ci.yml` file:
```yaml
include:
@@ -101,14 +84,17 @@ include:
The included template will create a `license_management` job in your CI/CD pipeline
and scan your dependencies to find their licenses.
-The report will be saved as a
+The results will be saved as a
[License Management report artifact](../../../ci/yaml/README.md#artifactsreportslicense_management-ultimate)
that you can later download and analyze. Due to implementation limitations, we
always take the latest License Management artifact available. Behind the scenes, the
[GitLab License Management Docker image](https://gitlab.com/gitlab-org/security-products/license-management)
is used to detect the languages/frameworks and in turn analyzes the licenses.
-#### Installing custom dependencies
+The License Management settings can be changed through environment variables by using the
+[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`. These variables are documented in the [License Management documentation](https://gitlab.com/gitlab-org/security-products/license-management#settings).
+
+### Installing custom dependencies
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.4.
@@ -136,7 +122,7 @@ variables:
In this example, `my-custom-install-script.sh` is a shell script at the root
directory of your project.
-#### Overriding the template
+### Overriding the template
If you want to override the job definition (for example, change properties like
`variables` or `dependencies`), you need to declare a `license_management` job
@@ -151,7 +137,7 @@ license_management:
CI_DEBUG_TRACE: "true"
```
-#### Configuring Maven projects
+### Configuring Maven projects
The License Management tool provides a `MAVEN_CLI_OPTS` environment variable which can hold
the command line arguments to pass to the `mvn install` command which is executed under the hood.
@@ -192,67 +178,6 @@ license_management:
LM_PYTHON_VERSION: 3
```
-### Manual job definition for GitLab 11.5 and later
-
-For GitLab 11.5 and GitLab Runner 11.5 and later, the following `license_management`
-job can be added:
-
-```yaml
-license_management:
- image:
- name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
- entrypoint: [""]
- stage: test
- allow_failure: true
- script:
- - /run.sh analyze .
- artifacts:
- reports:
- license_management: gl-license-management-report.json
-```
-
-If you want to install custom project dependencies via the `SETUP_CMD` variable:
-
-```yaml
-license_management:
- image:
- name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
- entrypoint: [""]
- stage: test
- variables:
- SETUP_CMD: ./my-custom-install-script.sh
- allow_failure: true
- script:
- - /run.sh analyze .
- artifacts:
- reports:
- license_management: gl-license-management-report.json
-```
-
-### Manual job definition for GitLab 11.4 and earlier (deprecated)
-
-CAUTION: **Caution:**
-Before GitLab 11.5, the License Management job and artifact had to be named specifically
-to automatically extract the report data and show it in the merge request widget.
-While these old job definitions are still maintained, they have been deprecated
-and may be removed in the next major release, GitLab 12.0. You are strongly advised
-to update your current `.gitlab-ci.yml` configuration to reflect that change.
-
-For GitLab 11.4 and earlier, the job should look like:
-
-```yaml
-license_management:
- image:
- name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
- entrypoint: [""]
- stage: test
- allow_failure: true
- script:
- - /run.sh analyze .
- artifacts:
- paths: [gl-license-management-report.json]
-```
-
## Project policies for License Management
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5940)
@@ -271,16 +196,15 @@ To approve or blacklist a license:
1. Click the **Add a license** button.
![License Management Add License](img/license_management_add_license.png)
+
1. In the **License name** dropdown, either:
- - Select one of the available licenses. You can search for licenses in the field
- at the top of the list.
- - Enter arbitrary text in the field at the top of the list. This will cause the text to be
- added as a license name to the list.
+ - Select one of the available licenses. You can search for licenses in the field
+ at the top of the list.
+ - Enter arbitrary text in the field at the top of the list. This will cause the text to be
+ added as a license name to the list.
1. Select the **Approve** or **Blacklist** radio button to approve or blacklist respectively
the selected license.
-
-
To modify an existing license:
1. In the **License Management** list, click the **Approved/Declined** dropdown to change it to the desired status.
@@ -293,8 +217,6 @@ Searching for Licenses:
![License Management Search](img/license_management_search.png)
-
-
## License Management report under pipelines
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5491)
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 84b45cbe6e6..1f9fd9d4e18 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -13,7 +13,7 @@ to learn how to protect your organization.
If you are using [GitLab CI/CD](../../../ci/README.md), you can analyze your source code for known
vulnerabilities using Static Application Security Testing (SAST).
-You can take advantage of SAST by either [including the CI job](#configuring-sast) in
+You can take advantage of SAST by either [including the CI job](#configuration) in
your existing `.gitlab-ci.yml` file or by implicitly using
[Auto SAST](../../../topics/autodevops/index.md#auto-sast-ultimate)
that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
@@ -73,30 +73,16 @@ The Java analyzers can also be used for variants like the
[Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html),
[Grails](https://grails.org/) and the [Maven wrapper](https://github.com/takari/maven-wrapper).
-## Configuring SAST
+## Configuration
-To enable SAST in your project, define a job in your `.gitlab-ci.yml` file that generates the
-[SAST report artifact](../../../ci/yaml/README.md#artifactsreportssast-ultimate).
+For GitLab 11.9 and later, to enable SAST, you must
+[include](../../../ci/yaml/README.md#includetemplate) the
+[`SAST.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml)
+that's provided as a part of your GitLab installation.
+For GitLab versions earlier than 11.9, you can copy and use the job as defined
+that template.
-This can be done in two ways:
-
-- For GitLab 11.9 and later, including the provided `SAST.gitlab-ci.yml` template (recommended).
-- Manually specifying the job definition. Not recommended unless using GitLab
- 11.8 and earlier.
-
-### Including the provided template
-
-NOTE: **Note:**
-The CI/CD SAST template is supported on GitLab 11.9 and later versions.
-For earlier versions, use the [manual job definition](#manual-job-definition-for-gitlab-115-and-later).
-
-A CI/CD [SAST template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml)
-with the default SAST job definition is provided as a part of your GitLab
-installation which you can [include](../../../ci/yaml/README.md#includetemplate)
-in your `.gitlab-ci.yml` file.
-
-To enable SAST using the provided template, add the following to your `.gitlab-ci.yml`
-file:
+Add the following to your `.gitlab-ci.yml` file:
```yaml
include:
@@ -106,14 +92,14 @@ include:
The included template will create a `sast` job in your CI/CD pipeline and scan
your project's source code for possible vulnerabilities.
-The report will be saved as a
+The results will be saved as a
[SAST report artifact](../../../ci/yaml/README.md#artifactsreportssast-ultimate)
that you can later download and analyze. Due to implementation limitations, we
always take the latest SAST artifact available. Behind the scenes, the
[GitLab SAST Docker image](https://gitlab.com/gitlab-org/security-products/sast)
is used to detect the languages/frameworks and in turn runs the matching scan tools.
-#### Customizing the SAST settings
+### Customizing the SAST settings
The SAST settings can be changed through environment variables by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
@@ -134,7 +120,7 @@ variables:
Because the template is [evaluated before](../../../ci/yaml/README.md#include)
the pipeline configuration, the last mention of the variable will take precedence.
-#### Overriding the SAST template
+### Overriding the SAST template
If you want to override the job definition (for example, change properties like
`variables` or `dependencies`), you need to declare a `sast` job after the
@@ -149,78 +135,6 @@ sast:
CI_DEBUG_TRACE: "true"
```
-### Manual job definition for GitLab 11.5 and later
-
-For GitLab 11.5 and GitLab Runner 11.5 and later, the following `sast`
-job can be added:
-
-```yaml
-sast:
- stage: test
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- allow_failure: true
- services:
- - docker:stable-dind
- script:
- - export SAST_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- - |
- docker run \
- --env SAST_ANALYZER_IMAGES \
- --env SAST_ANALYZER_IMAGE_PREFIX \
- --env SAST_ANALYZER_IMAGE_TAG \
- --env SAST_DEFAULT_ANALYZERS \
- --env SAST_EXCLUDED_PATHS \
- --env SAST_BANDIT_EXCLUDED_PATHS \
- --env SAST_BRAKEMAN_LEVEL \
- --env SAST_GOSEC_LEVEL \
- --env SAST_FLAWFINDER_LEVEL \
- --env SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
- --env SAST_PULL_ANALYZER_IMAGE_TIMEOUT \
- --env SAST_RUN_ANALYZER_TIMEOUT \
- --volume "$PWD:/code" \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/sast:$SAST_VERSION" /app/bin/run /code
- dependencies: []
- artifacts:
- reports:
- sast: gl-sast-report.json
-```
-
-You can supply many other [settings variables](https://gitlab.com/gitlab-org/security-products/sast#settings)
-via `docker run --env` to customize your job execution.
-
-### Manual job definition for GitLab 11.4 and earlier (deprecated)
-
-CAUTION: **Deprecated:**
-Before GitLab 11.5, the SAST job and artifact had to be named specifically
-to automatically extract report data and show it in the merge request widget.
-While these old job definitions are still maintained, they have been deprecated
-and may be removed in the next major release, GitLab 12.0. You are strongly
-advised to update your current `.gitlab-ci.yml` configuration to reflect that change.
-
-For GitLab 11.4 and earlier, the SAST job should look like:
-
-```yaml
-sast:
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- allow_failure: true
- services:
- - docker:stable-dind
- script:
- - export SAST_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- - docker run
- --env SAST_CONFIDENCE_LEVEL="${SAST_CONFIDENCE_LEVEL:-3}"
- --volume "$PWD:/code"
- --volume /var/run/docker.sock:/var/run/docker.sock
- "registry.gitlab.com/gitlab-org/security-products/sast:$SAST_VERSION" /app/bin/run /code
- artifacts:
- paths: [gl-sast-report.json]
-```
-
## Reports JSON format
CAUTION: **Caution:**
diff --git a/doc/user/asciidoc.md b/doc/user/asciidoc.md
index 06cc64b209d..df86b2a1cbe 100644
--- a/doc/user/asciidoc.md
+++ b/doc/user/asciidoc.md
@@ -170,6 +170,7 @@ Attach a block or paragraph to a list item using a list continuation (which you
* [x] checked
* [ ] not checked
```
+
#### Callout
```asciidoc
@@ -188,6 +189,7 @@ first term:: description of first term
second term::
description of second term
```
+
### Document Structure
#### Header
@@ -197,6 +199,7 @@ description of second term
Author Name <author@example.org>
v1.0, 2019-01-01
```
+
#### Sections
```asciidoc
@@ -217,6 +220,7 @@ include::basics.adoc[]
// define -a allow-uri-read to allow content to be read from URI
include::https://example.org/installation.adoc[]
```
+
### Blocks
```asciidoc
@@ -273,11 +277,11 @@ source - a listing that is embellished with (colorized) syntax highlighting
----
```
-```asciidoc
+````asciidoc
\```language
fenced code - a shorthand syntax for the source block
\```
-```
+````
```asciidoc
[,attribution,citetitle]
@@ -369,4 +373,3 @@ video::300817511[vimeo]
// page break
<<<
```
-
diff --git a/doc/user/award_emojis.md b/doc/user/award_emojis.md
index e4fd08a582c..1b1d126b726 100644
--- a/doc/user/award_emojis.md
+++ b/doc/user/award_emojis.md
@@ -7,7 +7,7 @@
When you're collaborating online, you get fewer opportunities for high-fives
and thumbs-ups. Emoji can be awarded to [issues](project/issues/index.md), [merge requests](project/merge_requests/index.md),
-[snippets](snippets.md), and anywhere you can have a discussion.
+[snippets](snippets.md), and anywhere you can have a thread.
![Award emoji](img/award_emoji_select.png)
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index 2246ea8ed5a..6956086c382 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -251,6 +251,7 @@ The applications below can be uninstalled.
| Application | GitLab version | Notes |
| ----------- | -------------- | ----- |
+| GitLab Runner | 12.2+ | Any running pipelines will be canceled. |
| Ingress | 12.1+ | The associated load balancer and IP will be deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. |
| JupyterHub | 12.1+ | All data not committed to GitLab will be deleted and cannot be restored. |
| Prometheus | 11.11+ | All data will be deleted and cannot be restored. |
diff --git a/doc/user/discussions/img/automatically_resolve_outdated_discussions.png b/doc/user/discussions/img/automatically_resolve_outdated_discussions.png
index ba129e7a618..d31216a7e2e 100644
--- a/doc/user/discussions/img/automatically_resolve_outdated_discussions.png
+++ b/doc/user/discussions/img/automatically_resolve_outdated_discussions.png
Binary files differ
diff --git a/doc/user/discussions/img/btn_new_issue_for_all_discussions.png b/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
deleted file mode 100644
index 3306bf2e60e..00000000000
--- a/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/discussions/img/btn_new_issue_for_all_threads.png b/doc/user/discussions/img/btn_new_issue_for_all_threads.png
new file mode 100644
index 00000000000..f24c84a2348
--- /dev/null
+++ b/doc/user/discussions/img/btn_new_issue_for_all_threads.png
Binary files differ
diff --git a/doc/user/discussions/img/commit_comment_mr_context.png b/doc/user/discussions/img/commit_comment_mr_context.png
index b363e0035e8..7b87d6e44d7 100644
--- a/doc/user/discussions/img/commit_comment_mr_context.png
+++ b/doc/user/discussions/img/commit_comment_mr_context.png
Binary files differ
diff --git a/doc/user/discussions/img/commit_comment_mr_discussions_tab.png b/doc/user/discussions/img/commit_comment_mr_discussions_tab.png
index 2b06cdcc055..4798ff4b658 100644
--- a/doc/user/discussions/img/commit_comment_mr_discussions_tab.png
+++ b/doc/user/discussions/img/commit_comment_mr_discussions_tab.png
Binary files differ
diff --git a/doc/user/discussions/img/discussion_comment.png b/doc/user/discussions/img/discussion_comment.png
index 206ddebf54b..685c30e5004 100644
--- a/doc/user/discussions/img/discussion_comment.png
+++ b/doc/user/discussions/img/discussion_comment.png
Binary files differ
diff --git a/doc/user/discussions/img/discussion_view.png b/doc/user/discussions/img/discussion_view.png
deleted file mode 100644
index 3a2b766ed7e..00000000000
--- a/doc/user/discussions/img/discussion_view.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/discussions/img/image_resolved_discussion.png b/doc/user/discussions/img/image_resolved_discussion.png
index ed00b5c77fe..9feded27c92 100644
--- a/doc/user/discussions/img/image_resolved_discussion.png
+++ b/doc/user/discussions/img/image_resolved_discussion.png
Binary files differ
diff --git a/doc/user/discussions/img/merge_request_commits_tab.png b/doc/user/discussions/img/merge_request_commits_tab.png
index 41a3648f390..065d4be61f0 100644
--- a/doc/user/discussions/img/merge_request_commits_tab.png
+++ b/doc/user/discussions/img/merge_request_commits_tab.png
Binary files differ
diff --git a/doc/user/discussions/img/mr_review_resolve.png b/doc/user/discussions/img/mr_review_resolve.png
index 34176f3fa8e..fc6299961a5 100644
--- a/doc/user/discussions/img/mr_review_resolve.png
+++ b/doc/user/discussions/img/mr_review_resolve.png
Binary files differ
diff --git a/doc/user/discussions/img/mr_review_resolve2.png b/doc/user/discussions/img/mr_review_resolve2.png
index e4adb5f2c2d..1794b682911 100644
--- a/doc/user/discussions/img/mr_review_resolve2.png
+++ b/doc/user/discussions/img/mr_review_resolve2.png
Binary files differ
diff --git a/doc/user/discussions/img/mr_review_second_comment.png b/doc/user/discussions/img/mr_review_second_comment.png
index 920ea05ad66..204cc840d9e 100644
--- a/doc/user/discussions/img/mr_review_second_comment.png
+++ b/doc/user/discussions/img/mr_review_second_comment.png
Binary files differ
diff --git a/doc/user/discussions/img/mr_review_second_comment_added.png b/doc/user/discussions/img/mr_review_second_comment_added.png
index 1fb54348547..aa15ca7fb98 100644
--- a/doc/user/discussions/img/mr_review_second_comment_added.png
+++ b/doc/user/discussions/img/mr_review_second_comment_added.png
Binary files differ
diff --git a/doc/user/discussions/img/mr_review_start.png b/doc/user/discussions/img/mr_review_start.png
index 38b44bda0d2..0f52bee7d89 100644
--- a/doc/user/discussions/img/mr_review_start.png
+++ b/doc/user/discussions/img/mr_review_start.png
Binary files differ
diff --git a/doc/user/discussions/img/mr_review_unresolve.png b/doc/user/discussions/img/mr_review_unresolve.png
index da895ceb89f..3441efc1572 100644
--- a/doc/user/discussions/img/mr_review_unresolve.png
+++ b/doc/user/discussions/img/mr_review_unresolve.png
Binary files differ
diff --git a/doc/user/discussions/img/new_issue_for_thread.png b/doc/user/discussions/img/new_issue_for_thread.png
new file mode 100644
index 00000000000..2264da0b5b5
--- /dev/null
+++ b/doc/user/discussions/img/new_issue_for_thread.png
Binary files differ
diff --git a/doc/user/discussions/img/onion_skin_view.png b/doc/user/discussions/img/onion_skin_view.png
index 91c3b396844..9bb4428184e 100644
--- a/doc/user/discussions/img/onion_skin_view.png
+++ b/doc/user/discussions/img/onion_skin_view.png
Binary files differ
diff --git a/doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.png b/doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.png
new file mode 100644
index 00000000000..9314e3a6490
--- /dev/null
+++ b/doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.png
Binary files differ
diff --git a/doc/user/discussions/img/pending_review_comment.png b/doc/user/discussions/img/pending_review_comment.png
index 916ef5b7452..812e4ac966a 100644
--- a/doc/user/discussions/img/pending_review_comment.png
+++ b/doc/user/discussions/img/pending_review_comment.png
Binary files differ
diff --git a/doc/user/discussions/img/preview_issue_for_thread.png b/doc/user/discussions/img/preview_issue_for_thread.png
new file mode 100644
index 00000000000..1517902c61c
--- /dev/null
+++ b/doc/user/discussions/img/preview_issue_for_thread.png
Binary files differ
diff --git a/doc/user/discussions/img/preview_issue_for_threads.png b/doc/user/discussions/img/preview_issue_for_threads.png
new file mode 100644
index 00000000000..8359ab3143c
--- /dev/null
+++ b/doc/user/discussions/img/preview_issue_for_threads.png
Binary files differ
diff --git a/doc/user/discussions/img/resolve_comment_button.png b/doc/user/discussions/img/resolve_comment_button.png
index 7c19fac31a2..0319ec999fd 100644
--- a/doc/user/discussions/img/resolve_comment_button.png
+++ b/doc/user/discussions/img/resolve_comment_button.png
Binary files differ
diff --git a/doc/user/discussions/img/resolve_thread_button.png b/doc/user/discussions/img/resolve_thread_button.png
new file mode 100644
index 00000000000..873c302f570
--- /dev/null
+++ b/doc/user/discussions/img/resolve_thread_button.png
Binary files differ
diff --git a/doc/user/discussions/img/resolve_thread_issue_notice.png b/doc/user/discussions/img/resolve_thread_issue_notice.png
new file mode 100644
index 00000000000..c2a8fdebee7
--- /dev/null
+++ b/doc/user/discussions/img/resolve_thread_issue_notice.png
Binary files differ
diff --git a/doc/user/discussions/img/resolve_thread_open_issue.png b/doc/user/discussions/img/resolve_thread_open_issue.png
new file mode 100644
index 00000000000..be2a4365297
--- /dev/null
+++ b/doc/user/discussions/img/resolve_thread_open_issue.png
Binary files differ
diff --git a/doc/user/discussions/img/review_comment_quickactions.png b/doc/user/discussions/img/review_comment_quickactions.png
index bd9880c329a..df5c4dd0fcc 100644
--- a/doc/user/discussions/img/review_comment_quickactions.png
+++ b/doc/user/discussions/img/review_comment_quickactions.png
Binary files differ
diff --git a/doc/user/discussions/img/review_preview.png b/doc/user/discussions/img/review_preview.png
index 4bf53a81b9c..1b91506b477 100644
--- a/doc/user/discussions/img/review_preview.png
+++ b/doc/user/discussions/img/review_preview.png
Binary files differ
diff --git a/doc/user/discussions/img/swipe_view.png b/doc/user/discussions/img/swipe_view.png
index 82d6e52173c..287d52a0811 100644
--- a/doc/user/discussions/img/swipe_view.png
+++ b/doc/user/discussions/img/swipe_view.png
Binary files differ
diff --git a/doc/user/discussions/img/thread_view.png b/doc/user/discussions/img/thread_view.png
new file mode 100644
index 00000000000..8c1fd9d5acf
--- /dev/null
+++ b/doc/user/discussions/img/thread_view.png
Binary files differ
diff --git a/doc/user/discussions/img/threads_resolved.png b/doc/user/discussions/img/threads_resolved.png
new file mode 100644
index 00000000000..6ac815cf874
--- /dev/null
+++ b/doc/user/discussions/img/threads_resolved.png
Binary files differ
diff --git a/doc/user/discussions/img/two_up_view.png b/doc/user/discussions/img/two_up_view.png
index d9e90708e87..062a96723dd 100644
--- a/doc/user/discussions/img/two_up_view.png
+++ b/doc/user/discussions/img/two_up_view.png
Binary files differ
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index c6bc580fb8f..3cb765c0463 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -1,4 +1,4 @@
-# Discussions
+# Threads
The ability to contribute conversationally is offered throughout GitLab.
@@ -12,7 +12,7 @@ You can leave a comment in the following places:
- commit diffs
There are standard comments, and you also have the option to create a comment
-in the form of a threaded discussion. A comment can also be [turned into a discussion](#start-a-discussion-by-replying-to-a-standard-comment)
+in the form of a thread. A comment can also be [turned into a thread](#start-a-thread-by-replying-to-a-standard-comment)
when it receives a reply.
The comment area supports [Markdown] and [quick actions]. You can edit your own
@@ -21,41 +21,39 @@ higher can also edit a comment made by someone else.
You can also reply to a comment notification email to reply to the comment if
[Reply by email] is configured for your GitLab instance. Replying to a standard comment
-creates another standard comment. Replying to a discussion comment creates a reply in the
-discussion thread. Email replies support [Markdown] and [quick actions], just as if you replied from the web.
+creates another standard comment. Replying to a threaded comment creates a reply in the thread. Email replies support
+ [Markdown] and [quick actions], just as if you replied from the web.
-## Resolvable comments and discussions
+## Resolvable comments and threads
> **Notes:**
>
> - The main feature was [introduced][ce-5022] in GitLab 8.11.
-> - Resolvable discussions can be added only to merge request diffs.
+> - Resolvable threads can be added only to merge request diffs.
-Discussion resolution helps keep track of progress during planning or code review.
+Thread resolution helps keep track of progress during planning or code review.
-Every standard comment or discussion thread in merge requests, commits, commit diffs, and
+Every standard comment or thread in merge requests, commits, commit diffs, and
snippets is initially displayed as unresolved. They can then be individually resolved by anyone
with at least Developer access to the project or by the author of the change being reviewed.
-The need to resolve all standard comments or discussions prevents you from forgetting
-to address feedback and lets you hide discussions that are no longer relevant.
+The need to resolve all standard comments or threads prevents you from forgetting
+to address feedback and lets you hide threads that are no longer relevant.
-!["A discussion between two people on a piece of code"][discussion-view]
+!["A thread between two people on a piece of code"](img/thread_view.png)
-### Commit discussions in the context of a merge request
+### Commit threads in the context of a merge request
> [Introduced][ce-31847] in GitLab 10.3.
-For reviewers with commit-based workflow, it may be useful to add discussions to
-specific commit diffs in the context of a merge request. These discussions will
+For reviewers with commit-based workflow, it may be useful to add threads to
+specific commit diffs in the context of a merge request. These threads will
persist through a commit ID change when:
- force-pushing after a rebase
- amending a commit
-This functionality is also demonstrated in the video [How to use Merge Request Commit Discussions](https://www.youtube.com/watch?v=TviJH6oRboo).
-
-To create a commit diff discussion:
+To create a commit diff thread:
1. Navigate to the merge request **Commits** tab. A list of commits that
constitute the merge request will be shown.
@@ -67,141 +65,141 @@ To create a commit diff discussion:
![Commit diff discussion in merge request context](img/commit_comment_mr_context.png)
-1. Any discussions created this way will be shown in the merge request's
+1. Any threads created this way will be shown in the merge request's
**Discussions** tab and are resolvable.
![Merge request Discussions tab](img/commit_comment_mr_discussions_tab.png)
-Discussions created this way will only appear in the original merge request
+Threads created this way will only appear in the original merge request
and not when navigating to that commit under your project's
**Repository > Commits** page.
TIP: **Tip:**
-When a link of a commit reference is found in a discussion inside a merge
+When a link of a commit reference is found in a thread inside a merge
request, it will be automatically converted to a link in the context of the
current merge request.
-### Jumping between unresolved discussions
+### Jumping between unresolved threads
When a merge request has a large number of comments it can be difficult to track
-what remains unresolved. You can jump between unresolved discussions with the
-Jump button next to the Reply field on a discussion.
+what remains unresolved. You can jump between unresolved threads with the
+Jump button next to the Reply field on a thread.
-You can also jump to the first unresolved discussion from the button next to the
-resolved discussions tracker.
+You can also jump to the first unresolved thread from the button next to the
+resolved threads tracker.
-!["3/4 discussions resolved"][discussions-resolved]
+!["8/9 threads resolved"](img/threads_resolved.png)
-### Marking a comment or discussion as resolved
+### Marking a comment or thread as resolved
-You can mark a discussion as resolved by clicking the **Resolve discussion**
-button at the bottom of the discussion.
+You can mark a thread as resolved by clicking the **Resolve thread**
+button at the bottom of the thread.
-!["Resolve discussion" button][resolve-discussion-button]
+!["Resolve thread" button](img/resolve_thread_button.png)
Alternatively, you can mark each comment as resolved individually.
-!["Resolve comment" button][resolve-comment-button]
+!["Resolve comment" button](img/resolve_comment_button.png)
-### Move all unresolved discussions in a merge request to an issue
+### Move all unresolved threads in a merge request to an issue
> [Introduced][ce-8266] in GitLab 9.1
-To continue all open discussions from a merge request in a new issue, click the
-**Resolve all discussions in new issue** button.
+To continue all open threads from a merge request in a new issue, click the
+**Resolve all threads in new issue** button.
-![Open new issue for all unresolved discussions](img/btn_new_issue_for_all_discussions.png)
+![Open new issue for all unresolved threads](img/btn_new_issue_for_all_threads.png)
-Alternatively, when your project only accepts merge requests [when all discussions
-are resolved](#only-allow-merge-requests-to-be-merged-if-all-discussions-are-resolved),
+Alternatively, when your project only accepts merge requests [when all threads
+are resolved](#only-allow-merge-requests-to-be-merged-if-all-threads-are-resolved),
there will be an **open an issue to resolve them later** link in the merge
request widget.
-![Link in merge request widget](img/resolve_discussion_open_issue.png)
+![Link in merge request widget](img/resolve_thread_open_issue.png)
This will prepare an issue with its content referring to the merge request and
-the unresolved discussions.
+the unresolved threads.
-![Issue mentioning discussions in a merge request](img/preview_issue_for_discussions.png)
+![Issue mentioning threads in a merge request](img/preview_issue_for_threads.png)
-Hitting **Submit issue** will cause all discussions to be marked as resolved and
+Hitting **Submit issue** will cause all threads to be marked as resolved and
add a note referring to the newly created issue.
-![Mark discussions as resolved notice](img/resolve_discussion_issue_notice.png)
+![Mark threads as resolved notice](img/resolve_thread_issue_notice.png)
You can now proceed to merge the merge request from the UI.
-### Moving a single discussion to a new issue
+### Moving a single thread to a new issue
> [Introduced][ce-8266] in GitLab 9.1
-To create a new issue for a single discussion, you can use the **Resolve this
-discussion in a new issue** button.
+To create a new issue for a single thread, you can use the **Resolve this
+thread in a new issue** button.
-![Create issue for discussion](img/new_issue_for_discussion.png)
+![Create issue for thread](img/new_issue_for_thread.png)
This will direct you to a new issue prefilled with the content of the
-discussion, similar to the issues created for delegating multiple
-discussions at once. Saving the issue will mark the discussion as resolved and
-add a note to the merge request discussion referencing the new issue.
+thread, similar to the issues created for delegating multiple
+threads at once. Saving the issue will mark the thread as resolved and
+add a note to the merge request thread referencing the new issue.
-![New issue for a single discussion](img/preview_issue_for_discussion.png)
+![New issue for a single thread](img/preview_issue_for_thread.png)
-### Only allow merge requests to be merged if all discussions are resolved
+### Only allow merge requests to be merged if all threads are resolved
> [Introduced][ce-7125] in GitLab 8.14.
-You can prevent merge requests from being merged until all discussions are
+You can prevent merge requests from being merged until all threads are
resolved.
Navigate to your project's settings page, select the
-**Only allow merge requests to be merged if all discussions are resolved** check
+**Only allow merge requests to be merged if all threads are resolved** check
box and hit **Save** for the changes to take effect.
-![Only allow merge if all the discussions are resolved settings](img/only_allow_merge_if_all_discussions_are_resolved.png)
+![Only allow merge if all the threads are resolved settings](img/only_allow_merge_if_all_threads_are_resolved.png)
-From now on, you will not be able to merge from the UI until all discussions
+From now on, you will not be able to merge from the UI until all threads
are resolved.
-![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png)
+![Only allow merge if all the threads are resolved message](img/resolve_thread_open_issue.png)
-### Automatically resolve merge request diff discussions when they become outdated
+### Automatically resolve merge request diff threads when they become outdated
> [Introduced][ce-14053] in GitLab 10.0.
-You can automatically resolve merge request diff discussions on lines modified
+You can automatically resolve merge request diff threads on lines modified
with a new push.
Navigate to your project's settings page, select the **Automatically resolve
-merge request diffs discussions on lines changed with a push** check box and hit
+merge request diffs threads on lines changed with a push** check box and hit
**Save** for the changes to take effect.
-![Automatically resolve merge request diff discussions when they become outdated](img/automatically_resolve_outdated_discussions.png)
+![Automatically resolve merge request diff threads when they become outdated](img/automatically_resolve_outdated_discussions.png)
-From now on, any discussions on a diff will be resolved by default if a push
-makes that diff section outdated. Discussions on lines that don't change and
-top-level resolvable discussions are not automatically resolved.
+From now on, any threads on a diff will be resolved by default if a push
+makes that diff section outdated. Threads on lines that don't change and
+top-level resolvable threads are not automatically resolved.
-## Commit discussions
+## Commit threads
-You can add comments and discussion threads to a particular commit under your
+You can add comments and threads to a particular commit under your
project's **Repository > Commits**.
CAUTION: **Attention:**
-Discussions created this way will be lost if the commit ID changes after a
+Threads created this way will be lost if the commit ID changes after a
force push.
## Threaded discussions
> [Introduced][ce-7527] in GitLab 9.1.
-While resolvable discussions are only available to merge request diffs,
-discussions can also be added without a diff. You can start a specific
-discussion which will look like a thread, on issues, commits, snippets, and
+While resolvable threads are only available to merge request diffs,
+threads can also be added without a diff. You can start a specific
+thread which will look like a thread, on issues, commits, snippets, and
merge requests.
To start a threaded discussion, click on the **Comment** button toggle dropdown,
-select **Start discussion** and click **Start discussion** when you're ready to
+select **Start thread** and click **Start thread** when you're ready to
post the comment.
![Comment type toggle](img/comment_type_toggle.gif)
@@ -209,56 +207,57 @@ post the comment.
This will post a comment with a single thread to allow you to discuss specific
comments in greater detail.
-![Discussion comment](img/discussion_comment.png)
+![Thread comment](img/discussion_comment.png)
-## Image discussions
+## Image threads
> [Introduced][ce-14061] in GitLab 10.1.
-Sometimes a discussion is revolved around an image. With image discussions,
-you can easily target a specific coordinate of an image and start a discussion
-around it. Image discussions are available in merge requests and commit detail views.
+Sometimes a thread is revolved around an image. With image threads,
+you can easily target a specific coordinate of an image and start a thread
+around it. Image threads are available in merge requests and commit detail views.
-To start an image discussion, hover your mouse over the image. Your mouse pointer
+To start an image thread, hover your mouse over the image. Your mouse pointer
should convert into an icon, indicating that the image is available for commenting.
-Simply click anywhere on the image to create a new discussion.
+Simply click anywhere on the image to create a new thread.
-![Start image discussion](img/start_image_discussion.gif)
+![Start image thread](img/start_image_discussion.gif)
After you click on the image, a comment form will be displayed that would be the start
-of your discussion. Once you save your comment, you will see a new badge displayed on
-top of your image. This badge represents your discussion.
+of your thread. Once you save your comment, you will see a new badge displayed on
+top of your image. This badge represents your thread.
>**Note:**
-This discussion badge is typically associated with a number that is only used as a visual
-reference for each discussion. In the merge request discussion tab,
-this badge will be indicated with a comment icon since each discussion will render a new
+This thread badge is typically associated with a number that is only used as a visual
+reference for each thread. In the merge request thread tab,
+this badge will be indicated with a comment icon since each thread will render a new
image section.
-Image discussions also work on diffs that replace an existing image. In this diff view
-mode, you can toggle the different view modes and still see the discussion point badges.
+Image threads also work on diffs that replace an existing image. In this diff view
+mode, you can toggle the different view modes and still see the thread point badges.
| 2-up | Swipe | Onion Skin |
| :-----------: | :----------: | :----------: |
| ![2-up view](img/two_up_view.png) | ![swipe view](img/swipe_view.png) | ![onion skin view](img/onion_skin_view.png) |
-Image discussions also work well with resolvable discussions. Resolved discussions
+Image threads also work well with resolvable threads. Resolved threads
on diffs (not on the merge request discussion tab) will appear collapsed on page
load and will have a corresponding badge counter to match the counter on the image.
-![Image resolved discussion](img/image_resolved_discussion.png)
+![Image resolved thread](img/image_resolved_discussion.png)
## Lock discussions
> [Introduced][ce-14531] in GitLab 10.1.
-For large projects with many contributors, it may be useful to stop discussions
+For large projects with many contributors, it may be useful to stop threads
in issues or merge requests in these scenarios:
-- The project maintainer has already resolved the discussion and it is not helpful
- for continued feedback. The project maintainer has already directed new conversation
+- The project maintainer has already resolved the thread and it is not helpful
+ for continued feedback.
+- The project maintainer has already directed new conversation
to newer issues or merge requests.
-- The people participating in the discussion are trolling, abusive, or otherwise
+- The people participating in the thread are trolling, abusive, or otherwise
being unproductive.
In these cases, a user with Developer permissions or higher in the project can lock (and unlock)
@@ -300,7 +299,7 @@ in an MR and click on the **Start a review** button.
Once a review is started, you will see any comments that are part of this review marked `Pending`.
All comments that are part of a review show two buttons:
-- **Submit review**: Submits all comments that are part of the review, making them visible to other users.
+- **Finish review**: Submits all comments that are part of the review, making them visible to other users.
- **Add comment now**: Submits the specific comment as a regular comment instead of as part of the review.
![A comment that is part of a review](img/pending_review_comment.png)
@@ -317,20 +316,20 @@ This will add the comment to the review.
![Second review comment](img/mr_review_second_comment_added.png)
-### Resolving/Unresolving discussions
+### Resolving/Unresolving threads
-Review comments can also resolve/unresolve [resolvable discussions](#resolvable-comments-and-discussions).
+Review comments can also resolve/unresolve [resolvable threads](#resolvable-comments-and-threads).
When replying to a comment, you will see a checkbox that you can click in order to resolve or unresolve
-the discussion once published.
+the thread once published.
![Resolve checkbox](img/mr_review_resolve.png)
-![Unresolve checkbox](img/mr_review_unresolve.png)
-If a particular pending comment will resolve or unresolve the discussion, this will be shown on the pending
+If a particular pending comment will resolve or unresolve the thread, this will be shown on the pending
comment itself.
![Resolve status](img/mr_review_resolve2.png)
-![Unresolve status](img/mr_review_unresolve2.png)
+
+![Unresolve status](img/mr_review_unresolve.png)
### Submitting a review
@@ -356,7 +355,7 @@ Replying to this email will, consequentially, create a new comment on the associ
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/26723) in GitLab 11.5.
For issues with many comments like activity notes and user comments, sometimes
-finding useful information can be hard. There is a way to filter comments from single notes and discussions for merge requests and issues.
+finding useful information can be hard. There is a way to filter comments from single notes and threads for merge requests and issues.
From a merge request's **Discussion** tab, or from an epic/issue overview, find the filter's dropdown menu on the right side of the page, from which you can choose one of the following options:
@@ -376,7 +375,7 @@ from any device you're logged into.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/18008) in GitLab 11.6.
As a reviewer, you're able to suggest code changes with a simple
-markdown syntax in Merge Request Diff discussions. Then, the
+markdown syntax in Merge Request Diff threads. Then, the
Merge Request author (or other users with appropriate
[permission](../permissions.md)) is able to apply these
suggestions with a click, which will generate a commit in
@@ -399,7 +398,7 @@ the Merge Request authored by the user that applied them.
![Apply suggestions](img/suggestion.png)
Once the author applies a suggestion, it will be marked with the **Applied** label,
-the discussion will be automatically resolved, and GitLab will create a new commit
+the thread will be automatically resolved, and GitLab will create a new commit
with the message `Apply suggestion to <file-name>` and push the suggested change
directly into the codebase in the merge request's branch.
[Developer permission](../permissions.md) is required to do so.
@@ -413,8 +412,8 @@ Custom commit messages will be introduced by
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/53310) in GitLab 11.10.
Reviewers can also suggest changes to multiple lines with a single suggestion
-within Merge Request diff discussions by adjusting the range offsets. The
-offsets are relative to the position of the diff discussion, and specify the
+within Merge Request diff threads by adjusting the range offsets. The
+offsets are relative to the position of the diff thread, and specify the
range to be replaced by the suggestion when it is applied.
![Multi-line suggestion syntax](img/multi-line-suggestion-syntax.png)
@@ -430,25 +429,26 @@ Suggestions covering multiple lines are limited to 100 lines _above_ and 100
lines _below_ the commented diff line, allowing up to 200 changed lines per
suggestion.
-## Start a discussion by replying to a standard comment
+## Start a thread by replying to a standard comment
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/30299) in GitLab 11.9
-To reply to a standard (non-discussion) comment, you can use the **Reply to comment** button.
+To reply to a standard (non-thread) comment, you can use the **Reply to comment** button.
![Reply to comment button](img/reply_to_comment_button.png)
-The **Reply to comment** button is only displayed if you have permissions to reply to an existing discussion, or start a discussion from a standard comment.
+The **Reply to comment** button is only displayed if you have permissions to reply to an existing thread, or start a thread from a standard comment.
Clicking on the **Reply to comment** button will bring the reply area into focus and you can type your reply.
![Reply to comment feature](img/reply_to_comment.gif)
-Replying to a non-discussion comment will convert the non-discussion comment to a
-threaded discussion once the reply is submitted. This conversion is considered an edit
+Replying to a non-thread comment will convert the non-thread comment to a
+thread once the reply is submitted. This conversion is considered an edit
to the original comment, so a note about when it was last edited will appear underneath it.
-This feature only exists for Issues, Merge requests, and Epics. Commits, Snippets and Merge request diff discussions are not supported yet.
+This feature only exists for Issues, Merge requests, and Epics. Commits, Snippets and Merge request diff threads are
+not supported yet.
[ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022
[ce-7125]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7125
diff --git a/doc/user/group/custom_project_templates.md b/doc/user/group/custom_project_templates.md
index 8a85c375490..7cdba8cf2b5 100644
--- a/doc/user/group/custom_project_templates.md
+++ b/doc/user/group/custom_project_templates.md
@@ -24,7 +24,7 @@ project in the group will be available to every logged in user.
However, private projects will be available only if the user is a member of the project.
NOTE: **Note:**
-Projects of nested subgroups of a selected template source cannot be used.
+Only direct subgroups can be set as the template source. Projects of nested subgroups of a selected template source cannot be used.
Repository and database information that are copied over to each new project are
identical to the data exported with [GitLab's Project Import/Export](../project/settings/import_export.md).
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index 601ffd4947b..4ab562b655f 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -205,12 +205,12 @@ You may also consult the [group permissions table][permissions].
These text fields also fully support
[GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm).
-## Comment, or start a discussion
+## Comment, or start a thread
Once you wrote your comment, you can either:
- Click "Comment" and your comment will be published.
-- Click "Start discussion": start a thread within that epic's thread to discuss specific points.
+- Click "Start thread": start a thread within that epic's discussion to discuss specific points.
## Award emoji
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 2d408766db8..55c5a18db7d 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -27,23 +27,23 @@ The following identity providers are supported:
- [Group SSO](index.md) needs to be configured.
- The `scim_group` feature flag must be enabled:
- Run the following commands in a Rails console:
+ Run the following commands in a Rails console:
- ```sh
- # Omnibus GitLab
- gitlab-rails console
+ ```sh
+ # Omnibus GitLab
+ gitlab-rails console
- # Installation from source
- cd /home/git/gitlab
- sudo -u git -H bin/rails console RAILS_ENV=production
- ```
+ # Installation from source
+ cd /home/git/gitlab
+ sudo -u git -H bin/rails console RAILS_ENV=production
+ ```
- To enable SCIM for a group named `group_name`:
+ To enable SCIM for a group named `group_name`:
- ```ruby
- group = Group.find_by_full_path('group_name')
- Feature.enable(:group_scim, group)
- ```
+ ```ruby
+ group = Group.find_by_full_path('group_name')
+ Feature.enable(:group_scim, group)
+ ```
### GitLab configuration
@@ -85,26 +85,26 @@ You can then test the connection clicking on `Test Connection`.
1. Map the `userPricipalName` to `emails[type eq "work"].value` and `mailNickname` to
`userName`.
- Example configuration:
+ Example configuration:
- ![Azure's attribute mapping configuration](img/scim_attribute_mapping.png)
+ ![Azure's attribute mapping configuration](img/scim_attribute_mapping.png)
1. Click on **Show advanced options > Edit attribute list for AppName**.
1. Leave the `id` as the primary and only required field.
- NOTE: **Note:**
- `username` should neither be primary nor required as we don't support
- that field on GitLab SCIM yet.
+ NOTE: **Note:**
+ `username` should neither be primary nor required as we don't support
+ that field on GitLab SCIM yet.
- ![Azure's attribute advanced configuration](img/scim_advanced.png)
+ ![Azure's attribute advanced configuration](img/scim_advanced.png)
1. Save all the screens and, in the **Provisioning** step, set
the `Provisioning Status` to `ON`.
- NOTE: **Note:**
- You can control what is actually synced by selecting the `Scope`. For example,
- `Sync only assigned users and groups` will only sync the users assigned to
- the application (`Users and groups`), otherwise it will sync the whole Active Directory.
+ NOTE: **Note:**
+ You can control what is actually synced by selecting the `Scope`. For example,
+ `Sync only assigned users and groups` will only sync the users assigned to
+ the application (`Users and groups`), otherwise it will sync the whole Active Directory.
Once enabled, the synchronization details and any errors will appear on the
bottom of the **Provisioning** screen, together with a link to the audit logs.
diff --git a/doc/user/index.md b/doc/user/index.md
index 501d74c76d1..db2759727a5 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -124,12 +124,12 @@ merge requests, code snippets, and commits.
When performing inline reviews to implementations
to your codebase through merge requests you can
-gather feedback through [resolvable discussions](discussions/index.md#resolvable-comments-and-discussions).
+gather feedback through [resolvable threads](discussions/index.md#resolvable-comments-and-threads).
### GitLab Flavored Markdown (GFM)
Read through the [GFM documentation](markdown.md) to learn how to apply
-the best of GitLab Flavored Markdown in your discussions, comments,
+the best of GitLab Flavored Markdown in your threads, comments,
issues and merge requests descriptions, and everywhere else GMF is
supported.
@@ -148,7 +148,7 @@ requests you're assigned to.
[Snippets](snippets.md) are code blocks that you want to store in GitLab, from which
you have quick access to. You can also gather feedback on them through
-[discussions](#discussions).
+[Discussions](#Discussions).
## Integrations
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 83629fc2e4b..96e74125801 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -40,7 +40,7 @@ repositories are also processed with CommonMark. As of 11.8, the [Redcarpet Ruby
has been removed and all issues and comments, including those from pre-11.1, are now processed
using the [CommonMark Ruby Library](https://github.com/gjtorikian/commonmarker).
-The documentation website had its [markdown engine migrated from Redcarpet to Kramdown](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/108)
+The documentation website had its [markdown engine migrated from Redcarpet to Kramdown](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/108)
in October 2018.
You may have older issues, merge requests, or Markdown documents in your
@@ -556,7 +556,7 @@ Inline `code` has `back-ticks around` it.
Similarly, a whole block of code can be fenced with triple backticks ```` ``` ````,
triple tildes (`~~~`), or indended 4 or more spaces to achieve a similar effect for
-a larger body of code. test.
+a larger body of code.
~~~
```
@@ -586,9 +586,11 @@ def function():
print s
```
- Using 4 spaces
- is like using
- 3-backtick fences.
+```
+Using 4 spaces
+is like using
+3-backtick fences.
+```
~~~
Tildes are OK too.
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 1b279173d1c..619cf34b5c3 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -60,7 +60,7 @@ The following table depicts the various user permission levels in a project.
| View confidential issues | (*2*) | ✓ | ✓ | ✓ | ✓ |
| Assign issues | | ✓ | ✓ | ✓ | ✓ |
| Label issues | | ✓ | ✓ | ✓ | ✓ |
-| Lock issue discussions | | ✓ | ✓ | ✓ | ✓ |
+| Lock issue threads | | ✓ | ✓ | ✓ | ✓ |
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
| Manage related issues **(STARTER)** | | ✓ | ✓ | ✓ | ✓ |
| Create issue from vulnerability **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
@@ -81,7 +81,7 @@ The following table depicts the various user permission levels in a project.
| Create new merge request | | | ✓ | ✓ | ✓ |
| Assign merge requests | | | ✓ | ✓ | ✓ |
| Label merge requests | | | ✓ | ✓ | ✓ |
-| Lock merge request discussions | | | ✓ | ✓ | ✓ |
+| Lock merge request threads | | | ✓ | ✓ | ✓ |
| Manage/Accept merge requests | | | ✓ | ✓ | ✓ |
| Create new environments | | | ✓ | ✓ | ✓ |
| Stop environments | | | ✓ | ✓ | ✓ |
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index e3e8c9a0d6d..d3a634c7b9d 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -183,29 +183,29 @@ a new set of recovery codes with SSH:
1. You will then be prompted to confirm that you want to generate new codes.
Continuing this process invalidates previously saved codes:
- ```sh
- Are you sure you want to generate new two-factor recovery codes?
- Any existing recovery codes you saved will be invalidated. (yes/no)
-
- yes
-
- Your two-factor authentication recovery codes are:
-
- 119135e5a3ebce8e
- 11f6v2a498810dcd
- 3924c7ab2089c902
- e79a3398bfe4f224
- 34bd7b74adbc8861
- f061691d5107df1a
- 169bf32a18e63e7f
- b510e7422e81c947
- 20dbed24c5e74663
- df9d3b9403b9c9f0
-
- During sign in, use one of the codes above when prompted for your
- two-factor code. Then, visit your Profile Settings and add a new device
- so you do not lose access to your account again.
- ```
+ ```sh
+ Are you sure you want to generate new two-factor recovery codes?
+ Any existing recovery codes you saved will be invalidated. (yes/no)
+
+ yes
+
+ Your two-factor authentication recovery codes are:
+
+ 119135e5a3ebce8e
+ 11f6v2a498810dcd
+ 3924c7ab2089c902
+ e79a3398bfe4f224
+ 34bd7b74adbc8861
+ f061691d5107df1a
+ 169bf32a18e63e7f
+ b510e7422e81c947
+ 20dbed24c5e74663
+ df9d3b9403b9c9f0
+
+ During sign in, use one of the codes above when prompted for your
+ two-factor code. Then, visit your Profile Settings and add a new device
+ so you do not lose access to your account again.
+ ```
1. Go to the GitLab sign-in page and enter your username/email and password.
When prompted for a two-factor code, enter one of the recovery codes obtained
diff --git a/doc/user/project/clusters/eks_and_gitlab/index.md b/doc/user/project/clusters/eks_and_gitlab/index.md
index ea09f9f1547..55a9fbabf98 100644
--- a/doc/user/project/clusters/eks_and_gitlab/index.md
+++ b/doc/user/project/clusters/eks_and_gitlab/index.md
@@ -40,97 +40,97 @@ then click **Add an existing Kubernetes cluster**.
A few details from the EKS cluster will be required to connect it to GitLab:
-1. **Retrieve the certificate**: A valid Kubernetes certificate is needed to
- authenticate to the EKS cluster. We will use the certificate created by default.
- Open a shell and use `kubectl` to retrieve it:
+1. **Retrieve the certificate**: A valid Kubernetes certificate is needed to
+ authenticate to the EKS cluster. We will use the certificate created by default.
+ Open a shell and use `kubectl` to retrieve it:
- - List the secrets with `kubectl get secrets`, and one should named similar to
- `default-token-xxxxx`. Copy that token name for use below.
- - Get the certificate with:
+ - List the secrets with `kubectl get secrets`, and one should named similar to
+ `default-token-xxxxx`. Copy that token name for use below.
+ - Get the certificate with:
- ```sh
- kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
- ```
-
-1. **Create admin token**: A `cluster-admin` token is required to install and
- manage Helm Tiller. GitLab establishes mutual SSL auth with Helm Tiller
- and creates limited service accounts for each application. To create the
- token we will create an admin service account as follows:
-
- 2.1. Create a file called `eks-admin-service-account.yaml` with contents:
-
- ```yaml
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: eks-admin
- namespace: kube-system
- ```
-
- 2.2. Apply the service account to your cluster:
-
- ```bash
- kubectl apply -f eks-admin-service-account.yaml
+ ```sh
+ kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
```
- Output:
-
- ```bash
- serviceaccount "eks-admin" created
- ```
-
- 2.3. Create a file called `eks-admin-cluster-role-binding.yaml` with contents:
-
- ```yaml
- apiVersion: rbac.authorization.k8s.io/v1beta1
- kind: ClusterRoleBinding
- metadata:
- name: eks-admin
- roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: cluster-admin
- subjects:
- - kind: ServiceAccount
- name: eks-admin
- namespace: kube-system
- ```
-
- 2.4. Apply the cluster role binding to your cluster:
-
- ```bash
- kubectl apply -f eks-admin-cluster-role-binding.yaml
- ```
-
- Output:
-
- ```bash
- clusterrolebinding "eks-admin" created
- ```
-
- 2.5. Retrieve the token for the `eks-admin` service account:
-
- ```bash
- kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')
- ```
-
- Copy the `<authentication_token>` value from the output:
-
- ```yaml
- Name: eks-admin-token-b5zv4
- Namespace: kube-system
- Labels: <none>
- Annotations: kubernetes.io/service-account.name=eks-admin
- kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
-
- Type: kubernetes.io/service-account-token
-
- Data
- ====
- ca.crt: 1025 bytes
- namespace: 11 bytes
- token: <authentication_token>
- ```
+1. **Create admin token**: A `cluster-admin` token is required to install and
+ manage Helm Tiller. GitLab establishes mutual SSL auth with Helm Tiller
+ and creates limited service accounts for each application. To create the
+ token we will create an admin service account as follows:
+
+ 2.1. Create a file called `eks-admin-service-account.yaml` with contents:
+
+ ```yaml
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: eks-admin
+ namespace: kube-system
+ ```
+
+ 2.2. Apply the service account to your cluster:
+
+ ```bash
+ kubectl apply -f eks-admin-service-account.yaml
+ ```
+
+ Output:
+
+ ```bash
+ serviceaccount "eks-admin" created
+ ```
+
+ 2.3. Create a file called `eks-admin-cluster-role-binding.yaml` with contents:
+
+ ```yaml
+ apiVersion: rbac.authorization.k8s.io/v1beta1
+ kind: ClusterRoleBinding
+ metadata:
+ name: eks-admin
+ roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cluster-admin
+ subjects:
+ - kind: ServiceAccount
+ name: eks-admin
+ namespace: kube-system
+ ```
+
+ 2.4. Apply the cluster role binding to your cluster:
+
+ ```bash
+ kubectl apply -f eks-admin-cluster-role-binding.yaml
+ ```
+
+ Output:
+
+ ```bash
+ clusterrolebinding "eks-admin" created
+ ```
+
+ 2.5. Retrieve the token for the `eks-admin` service account:
+
+ ```bash
+ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')
+ ```
+
+ Copy the `<authentication_token>` value from the output:
+
+ ```yaml
+ Name: eks-admin-token-b5zv4
+ Namespace: kube-system
+ Labels: <none>
+ Annotations: kubernetes.io/service-account.name=eks-admin
+ kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
+
+ Type: kubernetes.io/service-account-token
+
+ Data
+ ====
+ ca.crt: 1025 bytes
+ namespace: 11 bytes
+ token: <authentication_token>
+ ```
1. The API server endpoint is also required, so GitLab can connect to the cluster.
This is displayed on the AWS EKS console, when viewing the EKS cluster details.
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 56f8257fbe7..4c247691757 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -56,8 +56,8 @@ new Kubernetes cluster to your project:
1. Navigate to your project's **Operations > Kubernetes** page.
- NOTE: **Note:**
- You need Maintainer [permissions] and above to access the Kubernetes page.
+ NOTE: **Note:**
+ You need Maintainer [permissions] and above to access the Kubernetes page.
1. Click **Add Kubernetes cluster**.
1. Click **Create with Google Kubernetes Engine**.
@@ -97,117 +97,119 @@ To add an existing Kubernetes cluster to your project:
1. Navigate to your project's **Operations > Kubernetes** page.
- NOTE: **Note:**
- You need Maintainer [permissions] and above to access the Kubernetes page.
+ NOTE: **Note:**
+ You need Maintainer [permissions] and above to access the Kubernetes page.
1. Click **Add Kubernetes cluster**.
1. Click **Add an existing Kubernetes cluster** and fill in the details:
- - **Kubernetes cluster name** (required) - The name you wish to give the cluster.
- - **Environment scope** (required) - The
- [associated environment](#setting-the-environment-scope-premium) to this cluster.
- - **API URL** (required) -
- It's the URL that GitLab uses to access the Kubernetes API. Kubernetes
- exposes several APIs, we want the "base" URL that is common to all of them,
- e.g., `https://kubernetes.example.com` rather than `https://kubernetes.example.com/api/v1`.
-
- Get the API URL by running this command:
-
- ```sh
- kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'
- ```
- - **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the EKS cluster. We will use the certificate created by default.
- - List the secrets with `kubectl get secrets`, and one should named similar to
- `default-token-xxxxx`. Copy that token name for use below.
- - Get the certificate by running this command:
-
- ```sh
- kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
- ```
- - **Token** -
- GitLab authenticates against Kubernetes using service tokens, which are
- scoped to a particular `namespace`.
- **The token used should belong to a service account with
- [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
- privileges.** To create this service account:
-
- 1. Create a file called `gitlab-admin-service-account.yaml` with contents:
-
- ```yaml
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: gitlab-admin
- namespace: kube-system
- ---
- apiVersion: rbac.authorization.k8s.io/v1beta1
- kind: ClusterRoleBinding
- metadata:
- name: gitlab-admin
- roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: cluster-admin
- subjects:
- - kind: ServiceAccount
- name: gitlab-admin
- namespace: kube-system
- ```
-
- 1. Apply the service account and cluster role binding to your cluster:
-
- ```bash
- kubectl apply -f gitlab-admin-service-account.yaml
- ```
-
- Output:
-
- ```bash
- serviceaccount "gitlab-admin" created
- clusterrolebinding "gitlab-admin" created
- ```
-
- 1. Retrieve the token for the `gitlab-admin` service account:
-
- ```bash
- kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}')
- ```
-
- Copy the `<authentication_token>` value from the output:
-
- ```yaml
- Name: gitlab-admin-token-b5zv4
- Namespace: kube-system
- Labels: <none>
- Annotations: kubernetes.io/service-account.name=gitlab-admin
- kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
-
- Type: kubernetes.io/service-account-token
-
- Data
- ====
- ca.crt: 1025 bytes
- namespace: 11 bytes
- token: <authentication_token>
- ```
-
- NOTE: **Note:**
- For GKE clusters, you will need the
- `container.clusterRoleBindings.create` permission to create a cluster
- role binding. You can follow the [Google Cloud
- documentation](https://cloud.google.com/iam/docs/granting-changing-revoking-access)
- to grant access.
-
- - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster. See the [Managed clusters section](#gitlab-managed-clusters) for more information.
-
- - **Project namespace** (optional) - You don't have to fill it in; by leaving
- it blank, GitLab will create one for you. Also:
- - Each project should have a unique namespace.
- - The project namespace is not necessarily the namespace of the secret, if
- you're using a secret with broader permissions, like the secret from `default`.
- - You should **not** use `default` as the project namespace.
- - If you or someone created a secret specifically for the project, usually
- with limited permissions, the secret's namespace and project namespace may
- be the same.
+ - **Kubernetes cluster name** (required) - The name you wish to give the cluster.
+ - **Environment scope** (required) - The
+ [associated environment](#setting-the-environment-scope-premium) to this cluster.
+ - **API URL** (required) -
+ It's the URL that GitLab uses to access the Kubernetes API. Kubernetes
+ exposes several APIs, we want the "base" URL that is common to all of them,
+ e.g., `https://kubernetes.example.com` rather than `https://kubernetes.example.com/api/v1`.
+
+ Get the API URL by running this command:
+
+ ```sh
+ kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'
+ ```
+
+ - **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the EKS cluster. We will use the certificate created by default.
+ - List the secrets with `kubectl get secrets`, and one should named similar to
+ `default-token-xxxxx`. Copy that token name for use below.
+ - Get the certificate by running this command:
+
+ ```sh
+ kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
+ ```
+
+ - **Token** -
+ GitLab authenticates against Kubernetes using service tokens, which are
+ scoped to a particular `namespace`.
+ **The token used should belong to a service account with
+ [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
+ privileges.** To create this service account:
+
+ 1. Create a file called `gitlab-admin-service-account.yaml` with contents:
+
+ ```yaml
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: gitlab-admin
+ namespace: kube-system
+ ---
+ apiVersion: rbac.authorization.k8s.io/v1beta1
+ kind: ClusterRoleBinding
+ metadata:
+ name: gitlab-admin
+ roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cluster-admin
+ subjects:
+ - kind: ServiceAccount
+ name: gitlab-admin
+ namespace: kube-system
+ ```
+
+ 1. Apply the service account and cluster role binding to your cluster:
+
+ ```bash
+ kubectl apply -f gitlab-admin-service-account.yaml
+ ```
+
+ Output:
+
+ ```bash
+ serviceaccount "gitlab-admin" created
+ clusterrolebinding "gitlab-admin" created
+ ```
+
+ 1. Retrieve the token for the `gitlab-admin` service account:
+
+ ```bash
+ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}')
+ ```
+
+ Copy the `<authentication_token>` value from the output:
+
+ ```yaml
+ Name: gitlab-admin-token-b5zv4
+ Namespace: kube-system
+ Labels: <none>
+ Annotations: kubernetes.io/service-account.name=gitlab-admin
+ kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
+
+ Type: kubernetes.io/service-account-token
+
+ Data
+ ====
+ ca.crt: 1025 bytes
+ namespace: 11 bytes
+ token: <authentication_token>
+ ```
+
+ NOTE: **Note:**
+ For GKE clusters, you will need the
+ `container.clusterRoleBindings.create` permission to create a cluster
+ role binding. You can follow the [Google Cloud
+ documentation](https://cloud.google.com/iam/docs/granting-changing-revoking-access)
+ to grant access.
+
+ - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster. See the [Managed clusters section](#gitlab-managed-clusters) for more information.
+
+ - **Project namespace** (optional) - You don't have to fill it in; by leaving
+ it blank, GitLab will create one for you. Also:
+ - Each project should have a unique namespace.
+ - The project namespace is not necessarily the namespace of the secret, if
+ you're using a secret with broader permissions, like the secret from `default`.
+ - You should **not** use `default` as the project namespace.
+ - If you or someone created a secret specifically for the project, usually
+ with limited permissions, the secret's namespace and project namespace may
+ be the same.
1. Finally, click the **Create Kubernetes cluster** button.
diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md
index c67b12fb91a..c021d059d30 100644
--- a/doc/user/project/clusters/runbooks/index.md
+++ b/doc/user/project/clusters/runbooks/index.md
@@ -1,28 +1,27 @@
# Runbooks
-Runbooks are a collection of documented procedures that explain how to
-carry out a particular process, be it starting, stopping, debugging,
+Runbooks are a collection of documented procedures that explain how to
+carry out a particular process, be it starting, stopping, debugging,
or troubleshooting a particular system.
Using [Jupyter Notebooks](https://jupyter.org/) and the [Rubix library](https://github.com/Nurtch/rubix),
users can get started writing their own executable runbooks.
-
## Overview
-Historically, runbooks took the form of a decision tree or a detailed
-step-by-step guide depending on the condition or system.
+Historically, runbooks took the form of a decision tree or a detailed
+step-by-step guide depending on the condition or system.
-Modern implementations have introduced the concept of an "executable
-runbooks", where, along with a well-defined process, operators can execute
+Modern implementations have introduced the concept of an "executable
+runbooks", where, along with a well-defined process, operators can execute
pre-written code blocks or database queries against a given environment.
## Executable Runbooks
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/45912) in GitLab 11.4.
-The JupyterHub app offered via GitLab’s Kubernetes integration now ships
-with Nurtch’s Rubix library, providing a simple way to create DevOps
+The JupyterHub app offered via GitLab’s Kubernetes integration now ships
+with Nurtch’s Rubix library, providing a simple way to create DevOps
runbooks. A sample runbook is provided, showcasing common operations. While Rubix makes it
simple to create common Kubernetes and AWS workflows, you can also create them manually without
Rubix.
@@ -35,33 +34,33 @@ for an overview of how this is accomplished in GitLab!**
To create an executable runbook, you will need:
-1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications.
+1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications.
The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab).
-1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install
- all the other applications. It is installed in its own pod inside the cluster which
+1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install
+ all the other applications. It is installed in its own pod inside the cluster which
can run the helm CLI in a safe environment.
-1. **Ingress** - Ingress can provide load balancing, SSL termination, and name-based
+1. **Ingress** - Ingress can provide load balancing, SSL termination, and name-based
virtual hosting. It acts as a web proxy for your applications.
-1. **JupyterHub** - [JupyterHub](https://jupyterhub.readthedocs.io/) is a multi-user service for managing notebooks across
- a team. Jupyter Notebooks provide a web-based interactive programming environment
+1. **JupyterHub** - [JupyterHub](https://jupyterhub.readthedocs.io/) is a multi-user service for managing notebooks across
+ a team. Jupyter Notebooks provide a web-based interactive programming environment
used for data analysis, visualization, and machine learning.
## Nurtch
-Nurtch is the company behind the [Rubix library](https://github.com/Nurtch/rubix). Rubix is
-an open-source python library that makes it easy to perform common DevOps tasks inside Jupyter Notebooks.
-Tasks such as plotting Cloudwatch metrics and rolling your ECS/Kubernetes app are simplified
-down to a couple of lines of code. See the [Nurtch Documentation](http://docs.nurtch.com/en/latest)
+Nurtch is the company behind the [Rubix library](https://github.com/Nurtch/rubix). Rubix is
+an open-source python library that makes it easy to perform common DevOps tasks inside Jupyter Notebooks.
+Tasks such as plotting Cloudwatch metrics and rolling your ECS/Kubernetes app are simplified
+down to a couple of lines of code. See the [Nurtch Documentation](http://docs.nurtch.com/en/latest)
for more information.
## Configure an executable runbook with GitLab
-Follow this step-by-step guide to configure an executable runbook in GitLab using
+Follow this step-by-step guide to configure an executable runbook in GitLab using
the components outlined above and the preloaded demo runbook.
### 1. Add a Kubernetes cluster
-Follow the steps outlined in [Adding and creating a new GKE cluster via GitLab](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab)
+Follow the steps outlined in [Adding and creating a new GKE cluster via GitLab](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab)
to add a Kubernetes cluster to your project.
### 2. Install Helm Tiller, Ingress, and JupyterHub
@@ -80,13 +79,13 @@ Once Ingress has been installed successfully, click the **Install** button next
### 3. Login to JupyterHub and start the server
-Once JupyterHub has been installed successfully, navigate to the displayed **Jupyter Hostname** URL and click
-**Sign in with GitLab**. Authentication is automatically enabled for any user of the GitLab instance via OAuth2. This
+Once JupyterHub has been installed successfully, navigate to the displayed **Jupyter Hostname** URL and click
+**Sign in with GitLab**. Authentication is automatically enabled for any user of the GitLab instance via OAuth2. This
will redirect to GitLab in order to authorize JupyterHub to use your GitLab account. Click **Authorize**.
![authorize jupyter](img/authorize-jupyter.png)
-Once the application has been authorized you will taken back to the JupyterHub application. Click **Start My Server**.
+Once the application has been authorized you will taken back to the JupyterHub application. Click **Start My Server**.
The server will take a couple of seconds to start.
### 4. Configure access
@@ -103,7 +102,7 @@ Double-click the "Nurtch-DevOps-Demo.ipynb" runbook.
![sample runbook](img/sample-runbook.png)
-The contents on the runbook will be displayed on the right side of the screen. Under the "Setup" section, you will find
+The contents on the runbook will be displayed on the right side of the screen. Under the "Setup" section, you will find
entries for both your `PRIVATE_TOKEN` and your `PROJECT_ID`. Enter both these values, conserving the single quotes as follows:
```sql
@@ -111,7 +110,7 @@ PRIVATE_TOKEN = 'n671WNGecHugsdEDPsyo'
PROJECT_ID = '1234567'
```
-Update the `VARIABLE_NAME` on the last line of this section to match the name of the variable you are using for your
+Update the `VARIABLE_NAME` on the last line of this section to match the name of the variable you are using for your
access token. In this example our variable name is `PRIVATE_TOKEN`.
```sql
@@ -120,8 +119,8 @@ VARIABLE_VALUE = project.variables.get('PRIVATE_TOKEN').value
### 5. Configure an operation
-For this example we'll use the "**Run SQL queries in Notebook**" section in the sample runbook to query
-a postgres database. The first 4 lines of the section define the variables that are required for this query to function.
+For this example we'll use the "**Run SQL queries in Notebook**" section in the sample runbook to query
+a postgres database. The first 4 lines of the section define the variables that are required for this query to function.
```sql
%env DB_USER={project.variables.get('DB_USER').value}
@@ -134,10 +133,10 @@ Create the matching variables in your project's **Settings >> CI/CD >> Variables
![gitlab variables](img/gitlab-variables.png)
-Back in Jupyter, click the "Run SQL queries in Notebook" heading and the click *Run*. The results will be
+Back in Jupyter, click the "Run SQL queries in Notebook" heading and the click *Run*. The results will be
displayed in-line as follows:
![postgres query](img/postgres-query.png)
-You can try other operations such as running shell scripts or interacting with a Kubernetes cluster. Visit the
-[Nurtch Documentation](http://docs.nurtch.com/) for more information. \ No newline at end of file
+You can try other operations such as running shell scripts or interacting with a Kubernetes cluster. Visit the
+[Nurtch Documentation](http://docs.nurtch.com/) for more information.
diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md
index a8473f76733..14ee6303bf9 100644
--- a/doc/user/project/clusters/serverless/index.md
+++ b/doc/user/project/clusters/serverless/index.md
@@ -24,34 +24,34 @@ To run Knative on Gitlab, you will need:
1. **Existing GitLab project:** You will need a GitLab project to associate all resources. The simplest way to get started:
- - If you are planning on deploying functions, clone the [functions example project](https://gitlab.com/knative-examples/functions) to get started.
- - If you are planning on deploying a serverless application, clone the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started.
+ - If you are planning on deploying functions, clone the [functions example project](https://gitlab.com/knative-examples/functions) to get started.
+ - If you are planning on deploying a serverless application, clone the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started.
1. **Kubernetes Cluster:** An RBAC-enabled Kubernetes cluster is required to deploy Knative.
- The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab).
- The set of minimum recommended cluster specifications to run Knative is 3 nodes, 6 vCPUs, and 22.50 GB memory.
+ The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab).
+ The set of minimum recommended cluster specifications to run Knative is 3 nodes, 6 vCPUs, and 22.50 GB memory.
1. **Helm Tiller:** Helm is a package manager for Kubernetes and is required to install
- Knative.
+ Knative.
1. **GitLab Runner:** A runner is required to run the CI jobs that will deploy serverless
- applications or functions onto your cluster. You can install the GitLab Runner
- onto the existing Kubernetes cluster. See [Installing Applications](../index.md#installing-applications) for more information.
+ applications or functions onto your cluster. You can install the GitLab Runner
+ onto the existing Kubernetes cluster. See [Installing Applications](../index.md#installing-applications) for more information.
1. **Domain Name:** Knative will provide its own load balancer using Istio. It will provide an
- external IP address or hostname for all the applications served by Knative. You will be prompted to enter a
- wildcard domain where your applications will be served. Configure your DNS server to use the
- external IP address or hostname for that domain.
+ external IP address or hostname for all the applications served by Knative. You will be prompted to enter a
+ wildcard domain where your applications will be served. Configure your DNS server to use the
+ external IP address or hostname for that domain.
1. **`.gitlab-ci.yml`:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko)
- to build the application. We also use [gitlabktl](https://gitlab.com/gitlab-org/gitlabktl)
- and [TriggerMesh CLI](https://github.com/triggermesh/tm) CLIs to simplify the
- deployment of services and functions to Knative.
+ to build the application. We also use [gitlabktl](https://gitlab.com/gitlab-org/gitlabktl)
+ and [TriggerMesh CLI](https://github.com/triggermesh/tm) CLIs to simplify the
+ deployment of services and functions to Knative.
1. **`serverless.yml`** (for [functions only](#deploying-functions)): When using serverless to deploy functions, the `serverless.yml` file
- will contain the information for all the functions being hosted in the repository as well as a reference to the
- runtime being used.
+ will contain the information for all the functions being hosted in the repository as well as a reference to the
+ runtime being used.
1. **`Dockerfile`** (for [applications only](#deploying-serverless-applications): Knative requires a
- `Dockerfile` in order to build your applications. It should be included at the root of your
- project's repo and expose port `8080`. `Dockerfile` is not require if you plan to build serverless functions
- using our [runtimes](https://gitlab.com/gitlab-org/serverless/runtimes).
+ `Dockerfile` in order to build your applications. It should be included at the root of your
+ project's repo and expose port `8080`. `Dockerfile` is not require if you plan to build serverless functions
+ using our [runtimes](https://gitlab.com/gitlab-org/serverless/runtimes).
1. **Prometheus** (optional): Installing Prometheus allows you to monitor the scale and traffic of your serverless function/application.
- See [Installing Applications](../index.md#installing-applications) for more information.
+ See [Installing Applications](../index.md#installing-applications) for more information.
## Installing Knative via GitLab's Kubernetes integration
@@ -60,9 +60,9 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.
1. [Add a Kubernetes cluster](../index.md) and [install Helm](../index.md#installing-applications).
1. Once Helm has been successfully installed, scroll down to the Knative app section. Enter the domain to be used with
- your application/functions (e.g. `example.com`) and click **Install**.
+ your application/functions (e.g. `example.com`) and click **Install**.
- ![install-knative](img/install-knative.png)
+ ![install-knative](img/install-knative.png)
1. After the Knative installation has finished, you can wait for the IP address or hostname to be displayed in the
**Knative Endpoint** field or [retrieve the Istio Ingress Endpoint manually](../#manually-determining-the-external-endpoint).
@@ -77,7 +77,7 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.
if your Knative base domain is `knative.info` then you need to create an A record or CNAME record with domain `*.knative.info`
pointing the ip address or hostname of the ingress.
- ![dns entry](img/dns-entry.png)
+ ![dns entry](img/dns-entry.png)
NOTE: **Note:**
You can deploy either [functions](#deploying-functions) or [serverless applications](#deploying-serverless-applications)
@@ -100,54 +100,54 @@ You must do the following:
[add an existing Kubernetes cluster](../index.md#adding-an-existing-kubernetes-cluster).
1. Ensure GitLab can manage Knative:
- - For a non-GitLab managed cluster, ensure that the service account for the token
- provided can manage resources in the `serving.knative.dev` API group.
- - For a GitLab managed cluster, if you added the cluster in [GitLab 12.1 or later](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30235),
- then GitLab will already have the required access and you can proceed to the next step.
-
- Otherwise, you need to manually grant GitLab's service account the ability to manage
- resources in the `serving.knative.dev` API group. Since every GitLab service account
- has the `edit` cluster role, the simplest way to do this is with an
- [aggregated ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles)
- adding rules to the default `edit` cluster role: First, save the following YAML as
- `knative-serving-only-role.yaml`:
-
- ```yaml
- apiVersion: rbac.authorization.k8s.io/v1
- kind: ClusterRole
- metadata:
- name: knative-serving-only-role
- labels:
- rbac.authorization.k8s.io/aggregate-to-edit: "true"
- rules:
- - apiGroups:
- - serving.knative.dev
- resources:
- - configurations
- - configurationgenerations
- - routes
- - revisions
- - revisionuids
- - autoscalers
- - services
- verbs:
- - get
- - list
- - create
- - update
- - delete
- - patch
- - watch
- ```
-
- Then run the following command:
-
- ```bash
- kubectl apply -f knative-serving-only-role.yaml
- ```
-
- If you would rather grant permissions on a per service account basis, you can do this
- using a `Role` and `RoleBinding` specific to the service account and namespace.
+ - For a non-GitLab managed cluster, ensure that the service account for the token
+ provided can manage resources in the `serving.knative.dev` API group.
+ - For a GitLab managed cluster, if you added the cluster in [GitLab 12.1 or later](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30235),
+ then GitLab will already have the required access and you can proceed to the next step.
+
+ Otherwise, you need to manually grant GitLab's service account the ability to manage
+ resources in the `serving.knative.dev` API group. Since every GitLab service account
+ has the `edit` cluster role, the simplest way to do this is with an
+ [aggregated ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles)
+ adding rules to the default `edit` cluster role: First, save the following YAML as
+ `knative-serving-only-role.yaml`:
+
+ ```yaml
+ apiVersion: rbac.authorization.k8s.io/v1
+ kind: ClusterRole
+ metadata:
+ name: knative-serving-only-role
+ labels:
+ rbac.authorization.k8s.io/aggregate-to-edit: "true"
+ rules:
+ - apiGroups:
+ - serving.knative.dev
+ resources:
+ - configurations
+ - configurationgenerations
+ - routes
+ - revisions
+ - revisionuids
+ - autoscalers
+ - services
+ verbs:
+ - get
+ - list
+ - create
+ - update
+ - delete
+ - patch
+ - watch
+ ```
+
+ Then run the following command:
+
+ ```bash
+ kubectl apply -f knative-serving-only-role.yaml
+ ```
+
+ If you would rather grant permissions on a per service account basis, you can do this
+ using a `Role` and `RoleBinding` specific to the service account and namespace.
1. Follow the steps to deploy [functions](#deploying-functions)
or [serverless applications](#deploying-serverless-applications) onto your
@@ -157,9 +157,9 @@ You must do the following:
> Introduced in GitLab 11.6.
-Using functions is useful for dealing with independent
-events without needing to maintain a complex unified infrastructure. This allows
-you to focus on a single task that can be executed/scaled automatically and independently.
+Using functions is useful for dealing with independent events without needing
+to maintain a complex unified infrastructure. This allows you to focus on a
+single task that can be executed/scaled automatically and independently.
Currently the following [runtimes](https://gitlab.com/gitlab-org/serverless/runtimes) are offered:
@@ -167,15 +167,21 @@ Currently the following [runtimes](https://gitlab.com/gitlab-org/serverless/runt
- node.js
- Dockerfile
-You can find and import all the files referenced in this doc in the **[functions example project](https://gitlab.com/knative-examples/functions)**.
+`Dockerfile` presence is assumed when a runtime is not specified.
-Follow these steps to deploy a function using the Node.js runtime to your Knative instance (you can skip these steps if you've cloned the example project):
+You can find and import all the files referenced in this doc in the
+**[functions example project](https://gitlab.com/knative-examples/functions)**.
-1. Create a directory that will house the function. In this example we will create a directory called `echo` at the root of the project.
+Follow these steps to deploy a function using the Node.js runtime to your
+Knative instance (you can skip these steps if you've cloned the example
+project):
+
+1. Create a directory that will house the function. In this example we will
+ create a directory called `echo` at the root of the project.
1. Create the file that will contain the function code. In this example, our file is called `echo.js` and is located inside the `echo` directory. If your project is:
- - Public, continue to the next step.
- - Private, you will need to [create a GitLab deploy token](../../deploy_tokens/index.md#creating-a-deploy-token) with `gitlab-deploy-token` as the name and the `read_registry` scope.
+ - Public, continue to the next step.
+ - Private, you will need to [create a GitLab deploy token](../../deploy_tokens/index.md#creating-a-deploy-token) with `gitlab-deploy-token` as the name and the `read_registry` scope.
1. `.gitlab-ci.yml`: this defines a pipeline used to deploy your functions.
It must be included at the root of your repository:
@@ -193,16 +199,16 @@ Follow these steps to deploy a function using the Node.js runtime to your Knativ
environment: production
```
- This `.gitlab-ci.yml` creates jobs that invoke some predefined commands to
- build and deploy your functions to your cluster.
+ This `.gitlab-ci.yml` creates jobs that invoke some predefined commands to
+ build and deploy your functions to your cluster.
- `Serverless.gitlab-ci.yml` is a template that allows customization.
- You can either import it with `include` parameter and use `extends` to
- customize your jobs, or you can inline the entire template by choosing it
- from **Apply a template** dropdown when editing the `.gitlab-ci.yml` file through
- the user interface.
+ `Serverless.gitlab-ci.yml` is a template that allows customization.
+ You can either import it with `include` parameter and use `extends` to
+ customize your jobs, or you can inline the entire template by choosing it
+ from **Apply a template** dropdown when editing the `.gitlab-ci.yml` file through
+ the user interface.
-2. `serverless.yml`: this file contains the metadata for your functions,
+1. `serverless.yml`: this file contains the metadata for your functions,
such as name, runtime, and environment.
It must be included at the root of your repository.
@@ -248,21 +254,22 @@ Explanation of the fields used above:
### `functions`
-In the `serverless.yml` example above, the function name is `echo` and the subsequent lines contain the function attributes.
+In the `serverless.yml` example above, the function name is `echo` and the
+subsequent lines contain the function attributes.
| Parameter | Description |
|-----------|-------------|
| `handler` | The function's name. |
| `source` | Directory with sources of a functions. |
-| `runtime` | The runtime to be used to execute the function. |
+| `runtime` (optional)| The runtime to be used to execute the function. When the runtime is not specified, we assume that `Dockerfile` is present in the function directory specified by `source`. |
| `description` | A short description of the function. |
| `environment` | Sets an environment variable for the specific function only. |
-After the `gitlab-ci.yml` template has been added and the `serverless.yml` file has been
-created, pushing a commit to your project will result in a
-CI pipeline being executed which will deploy each function as a Knative service.
-Once the deploy stage has finished, additional details for the function will
-appear under **Operations > Serverless**.
+After the `gitlab-ci.yml` template has been added and the `serverless.yml` file
+has been created, pushing a commit to your project will result in a CI pipeline
+being executed which will deploy each function as a Knative service. Once the
+deploy stage has finished, additional details for the function will appear
+under **Operations > Serverless**.
![serverless page](img/serverless-page.png)
@@ -281,16 +288,17 @@ The sample function can now be triggered from any HTTP client using a simple `PO
1. Using curl (replace the URL on the last line with the URL of your application):
- ```bash
- curl \
- --header "Content-Type: application/json" \
- --request POST \
- --data '{"GitLab":"FaaS"}' \
- http://functions-echo.functions-1.functions.example.com/
- ```
- 2. Using a web-based tool (ie. postman, restlet, etc)
+ ```bash
+ curl \
+ --header "Content-Type: application/json" \
+ --request POST \
+ --data '{"GitLab":"FaaS"}' \
+ http://functions-echo.functions-1.functions.example.com/
+ ```
+
+ 1. Using a web-based tool (ie. postman, restlet, etc)
- ![function execution](img/function-execution.png)
+ ![function execution](img/function-execution.png)
## Deploying Serverless applications
@@ -319,6 +327,8 @@ customize your jobs, or you can inline the entire template by choosing it
from **Apply a template** dropdown when editing the `.gitlab-ci.yml` file through
the user interface.
+A `serverless.yml` file is not required when deploying serverless applications.
+
### Deploy the application with Knative
With all the pieces in place, the next time a CI pipeline runs, the Knative application will be deployed. Navigate to
@@ -392,259 +402,258 @@ The instructions below relate to installing and running Certbot on a Linux serve
[`certbot-auto` wrapper script](https://certbot.eff.org/docs/install.html#certbot-auto).
On the command line of your server, run the following commands:
- ```sh
- wget https://dl.eff.org/certbot-auto
- sudo mv certbot-auto /usr/local/bin/certbot-auto
- sudo chown root /usr/local/bin/certbot-auto
- chmod 0755 /usr/local/bin/certbot-auto
- /usr/local/bin/certbot-auto --help
- ```
-
- To check the integrity of the `certbot-auto` script, run:
-
- ```sh
- wget -N https://dl.eff.org/certbot-auto.asc
- gpg2 --keyserver ipv4.pool.sks-keyservers.net --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2
- gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc /usr/local/bin/certbot-auto
- ```
-
- The output of the last command should look something like:
-
- ```sh
- gpg: Signature made Mon 10 Jun 2019 06:24:40 PM EDT
- gpg: using RSA key A2CFB51FA275A7286234E7B24D17C995CD9775F2
- gpg: key 4D17C995CD9775F2 marked as ultimately trusted
- gpg: checking the trustdb
- gpg: marginals needed: 3 completes needed: 1 trust model: pgp
- gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
- gpg: next trustdb check due at 2027-11-22
- gpg: Good signature from "Let's Encrypt Client Team <letsencrypt-client@eff.org>" [ultimate]
- ```
+ ```sh
+ wget https://dl.eff.org/certbot-auto
+ sudo mv certbot-auto /usr/local/bin/certbot-auto
+ sudo chown root /usr/local/bin/certbot-auto
+ chmod 0755 /usr/local/bin/certbot-auto
+ /usr/local/bin/certbot-auto --help
+ ```
+
+ To check the integrity of the `certbot-auto` script, run:
+
+ ```sh
+ wget -N https://dl.eff.org/certbot-auto.asc
+ gpg2 --keyserver ipv4.pool.sks-keyservers.net --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2
+ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc /usr/local/bin/certbot-auto
+ ```
+
+ The output of the last command should look something like:
+
+ ```sh
+ gpg: Signature made Mon 10 Jun 2019 06:24:40 PM EDT
+ gpg: using RSA key A2CFB51FA275A7286234E7B24D17C995CD9775F2
+ gpg: key 4D17C995CD9775F2 marked as ultimately trusted
+ gpg: checking the trustdb
+ gpg: marginals needed: 3 completes needed: 1 trust model: pgp
+ gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
+ gpg: next trustdb check due at 2027-11-22
+ gpg: Good signature from "Let's Encrypt Client Team <letsencrypt-client@eff.org>" [ultimate]
+ ```
1. Run the following command to use Certbot to request a certificate
using DNS challenge during authorization:
+ ```sh
+ ./certbot-auto certonly --manual --preferred-challenges dns -d '*.<namespace>.example.com'
+ ```
+
+ Where `<namespace>` is the namespace created by GitLab for your serverless project (composed of `<projectname+id>`) and
+ `example.com` is the domain being used for your project. If you are unsure what the namespace of your project is, navigate
+ to the **Operations > Serverless** page of your project and inspect
+ the endpoint provided for your function/app.
+
+ ![function_endpoint](img/function-endpoint.png)
+
+ In the above image, the namespace for the project is `node-function-11909507` and the domain is `knative.info`, thus
+ certificate request line would look like this:
+
+ ```sh
+ ./certbot-auto certonly --manual --preferred-challenges dns -d '*.node-function-11909507.knative.info'
+ ```
- ```sh
- ./certbot-auto certonly --manual --preferred-challenges dns -d '*.<namespace>.example.com'
- ```
-
- Where `<namespace>` is the namespace created by GitLab for your serverless project (composed of `<projectname+id>`) and
- `example.com` is the domain being used for your project. If you are unsure what the namespace of your project is, navigate
- to the **Operations > Serverless** page of your project and inspect
- the endpoint provided for your function/app.
-
- ![function_endpoint](img/function-endpoint.png)
-
- In the above image, the namespace for the project is `node-function-11909507` and the domain is `knative.info`, thus
- certificate request line would look like this:
-
- ```sh
- ./certbot-auto certonly --manual --preferred-challenges dns -d '*.node-function-11909507.knative.info'
- ```
-
- The Certbot tool walks you through the steps of validating that you own each domain that you specify by creating TXT records in those domains.
- After this process is complete, the output should look something like this:
-
- ```sh
- IMPORTANT NOTES:
- - Congratulations! Your certificate and chain have been saved at:
- /etc/letsencrypt/live/namespace.example.com/fullchain.pem
- Your key file has been saved at:
- /etc/letsencrypt/live/namespace.example/privkey.pem
- Your cert will expire on 2019-09-19. To obtain a new or tweaked
- version of this certificate in the future, simply run certbot-auto
- again. To non-interactively renew *all* of your certificates, run
- "certbot-auto renew"
- -----BEGIN PRIVATE KEY-----
- - Your account credentials have been saved in your Certbot
- configuration directory at /etc/letsencrypt. You should make a
- secure backup of this folder now. This configuration directory will
- also contain certificates and private keys obtained by Certbot so
- making regular backups of this folder is ideal.
- ```
+ The Certbot tool walks you through the steps of validating that you own each domain that you specify by creating TXT records in those domains.
+ After this process is complete, the output should look something like this:
+
+ ```sh
+ IMPORTANT NOTES:
+ - Congratulations! Your certificate and chain have been saved at:
+ /etc/letsencrypt/live/namespace.example.com/fullchain.pem
+ Your key file has been saved at:
+ /etc/letsencrypt/live/namespace.example/privkey.pem
+ Your cert will expire on 2019-09-19. To obtain a new or tweaked
+ version of this certificate in the future, simply run certbot-auto
+ again. To non-interactively renew *all* of your certificates, run
+ "certbot-auto renew"
+ -----BEGIN PRIVATE KEY-----
+ - Your account credentials have been saved in your Certbot
+ configuration directory at /etc/letsencrypt. You should make a
+ secure backup of this folder now. This configuration directory will
+ also contain certificates and private keys obtained by Certbot so
+ making regular backups of this folder is ideal.
+ ```
1. Create certificate and private key files. Using the contents of the files
returned by Certbot, we'll create two files in order to create the
Kubernetes secret:
- Run the following command to see the contents of `fullchain.pem`:
-
- ```sh
- sudo cat /etc/letsencrypt/live/node-function-11909507.knative.info/fullchain.pem
- ```
-
- Output should look like this:
-
- ```sh
- -----BEGIN CERTIFICATE-----
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b4ag==
- -----END CERTIFICATE-----
- -----BEGIN CERTIFICATE-----
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- K2fcb195768c39e9a94cec2c2e30Qg==
- -----END CERTIFICATE-----
- ```
-
- Create a file with the name `cert.pem` with the contents of the entire output.
-
- Once `cert.pem` is created, run the following command to see the contents of `privkey.pem`:
-
- ```sh
- sudo cat /etc/letsencrypt/live/namespace.example/privkey.pem
- ```
-
- Output should look like this:
-
- ```sh
- -----BEGIN PRIVATE KEY-----
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
- -----BEGIN CERTIFICATE-----
- fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
- 4f294d1eaca42b8692017b4262==
- -----END PRIVATE KEY-----
- ```
-
- Create a new file with the name `cert.pk` with the contents of the entire output.
+ Run the following command to see the contents of `fullchain.pem`:
+
+ ```sh
+ sudo cat /etc/letsencrypt/live/node-function-11909507.knative.info/fullchain.pem
+ ```
+
+ Output should look like this:
+
+ ```sh
+ -----BEGIN CERTIFICATE-----
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b4ag==
+ -----END CERTIFICATE-----
+ -----BEGIN CERTIFICATE-----
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ K2fcb195768c39e9a94cec2c2e30Qg==
+ -----END CERTIFICATE-----
+ ```
+
+ Create a file with the name `cert.pem` with the contents of the entire output.
+
+ Once `cert.pem` is created, run the following command to see the contents of `privkey.pem`:
+
+ ```sh
+ sudo cat /etc/letsencrypt/live/namespace.example/privkey.pem
+ ```
+
+ Output should look like this:
+
+ ```sh
+ -----BEGIN PRIVATE KEY-----
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ -----BEGIN CERTIFICATE-----
+ fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 4f294d1eaca42b8692017b4262==
+ -----END PRIVATE KEY-----
+ ```
+
+ Create a new file with the name `cert.pk` with the contents of the entire output.
1. Create a Kubernetes secret to hold your TLS certificate, `cert.pem`, and
the private key `cert.pk`:
- NOTE: **Note:**
- Running `kubectl` commands on your cluster requires setting up access to the cluster first.
- For clusters created on GKE, see
- [GKE Cluster Access](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl).
- For other platforms, [install `kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
-
- ```sh
- kubectl create --namespace istio-system secret tls istio-ingressgateway-certs \
- --key cert.pk \
- --cert cert.pem
- ```
+ NOTE: **Note:**
+ Running `kubectl` commands on your cluster requires setting up access to the cluster first.
+ For clusters created on GKE, see
+ [GKE Cluster Access](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl).
+ For other platforms, [install `kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
+
+ ```sh
+ kubectl create --namespace istio-system secret tls istio-ingressgateway-certs \
+ --key cert.pk \
+ --cert cert.pem
+ ```
- Where `cert.pem` and `cert.pk` are your certificate and private key files. Note that the `istio-ingressgateway-certs` secret name is required.
+ Where `cert.pem` and `cert.pk` are your certificate and private key files. Note that the `istio-ingressgateway-certs` secret name is required.
1. Configure Knative to use the new secret that you created for HTTPS
connections. Run the
- following command to open the Knative shared `gateway` in edit mode:
-
- ```sh
- kubectl edit gateway knative-ingress-gateway --namespace knative-serving
- ```
-
- Update the gateway to include the following tls: section and configuration:
-
- ```sh
- tls:
- mode: SIMPLE
- privateKey: /etc/istio/ingressgateway-certs/tls.key
- serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
- ```
-
- Example:
-
- ```sh
- apiVersion: networking.istio.io/v1alpha3
- kind: Gateway
- metadata:
- # ... skipped ...
- spec:
- selector:
- istio: ingressgateway
- servers:
- - hosts:
- - "*"
- port:
- name: http
- number: 80
- protocol: HTTP
- - hosts:
- - "*"
- port:
- name: https
- number: 443
- protocol: HTTPS
- tls:
- mode: SIMPLE
- privateKey: /etc/istio/ingressgateway-certs/tls.key
- serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
- ```
-
- After your changes are running on your Knative cluster, you can begin using the HTTPS protocol for secure access your deployed Knative services.
- In the event a mistake is made during this process and you need to update the cert, you will need to edit the gateway `knative-ingress-gateway`
- to switch back to `PASSTHROUGH` mode. Once corrections are made, edit the file again so the gateway will use the new certificates.
+ following command to open the Knative shared `gateway` in edit mode:
+
+ ```sh
+ kubectl edit gateway knative-ingress-gateway --namespace knative-serving
+ ```
+
+ Update the gateway to include the following tls: section and configuration:
+
+ ```sh
+ tls:
+ mode: SIMPLE
+ privateKey: /etc/istio/ingressgateway-certs/tls.key
+ serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
+ ```
+
+ Example:
+
+ ```sh
+ apiVersion: networking.istio.io/v1alpha3
+ kind: Gateway
+ metadata:
+ # ... skipped ...
+ spec:
+ selector:
+ istio: ingressgateway
+ servers:
+ - hosts:
+ - "*"
+ port:
+ name: http
+ number: 80
+ protocol: HTTP
+ - hosts:
+ - "*"
+ port:
+ name: https
+ number: 443
+ protocol: HTTPS
+ tls:
+ mode: SIMPLE
+ privateKey: /etc/istio/ingressgateway-certs/tls.key
+ serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
+ ```
+
+ After your changes are running on your Knative cluster, you can begin using the HTTPS protocol for secure access your deployed Knative services.
+ In the event a mistake is made during this process and you need to update the cert, you will need to edit the gateway `knative-ingress-gateway`
+ to switch back to `PASSTHROUGH` mode. Once corrections are made, edit the file again so the gateway will use the new certificates.
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index 78ffa11d59b..96c4f16fe04 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -57,8 +57,8 @@ Example `CODEOWNERS` file:
# Files with a `#` can still be accesssed by escaping the pound sign
\#file_with_pound.rb @owner-file-with-pound
-# Multiple codeowners can be specified, separated by whitespace
-CODEOWNERS @multiple @owners @tab-separated
+# Multiple codeowners can be specified, separated by spaces or tabs
+CODEOWNERS @multiple @code @owners
# Both usernames or email addresses can be used to match
# users. Everything else will be ignored. For example this will
diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md
index eac7fc6b195..9368c56004d 100644
--- a/doc/user/project/container_registry.md
+++ b/doc/user/project/container_registry.md
@@ -241,10 +241,10 @@ The following installation instructions assume you are running Ubuntu:
Enter <kbd>CTRL</kbd>-<kbd>C</kbd> to quit.
1. Install the certificate from `~/.mitmproxy` to your system:
- ```sh
- sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem /usr/local/share/ca-certificates/mitmproxy-ca-cert.crt
- sudo update-ca-certificates
- ```
+ ```sh
+ sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem /usr/local/share/ca-certificates/mitmproxy-ca-cert.crt
+ sudo update-ca-certificates
+ ```
If successful, the output should indicate that a certificate was added:
diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md
index cb1faa771bc..0a83f2e894a 100644
--- a/doc/user/project/deploy_boards.md
+++ b/doc/user/project/deploy_boards.md
@@ -63,12 +63,12 @@ To display the Deploy Boards for a specific [environment] you should:
1. Have a Kubernetes cluster up and running.
- NOTE: **Running on OpenShift:**
- If you are using OpenShift, ensure that you're using the `Deployment` resource
- instead of `DeploymentConfiguration`, otherwise the Deploy Boards won't render
- correctly. For more information, read the
- [OpenShift docs](https://docs.openshift.com/container-platform/3.7/dev_guide/deployments/kubernetes_deployments.html#kubernetes-deployments-vs-deployment-configurations)
- and [GitLab issue #4584](https://gitlab.com/gitlab-org/gitlab-ee/issues/4584).
+ NOTE: **Running on OpenShift:**
+ If you are using OpenShift, ensure that you're using the `Deployment` resource
+ instead of `DeploymentConfiguration`, otherwise the Deploy Boards won't render
+ correctly. For more information, read the
+ [OpenShift docs](https://docs.openshift.com/container-platform/3.7/dev_guide/deployments/kubernetes_deployments.html#kubernetes-deployments-vs-deployment-configurations)
+ and [GitLab issue #4584](https://gitlab.com/gitlab-org/gitlab-ee/issues/4584).
1. [Configure GitLab Runner][runners] with the [Docker][docker-exec] or
[Kubernetes][kube-exec] executor.
@@ -93,7 +93,7 @@ To display the Deploy Boards for a specific [environment] you should:
To migrate, please apply the required annotations (see above) and
re-deploy your application.
- ![Deploy Boards Kubernetes Label](img/deploy_boards_kubernetes_label.png)
+ ![Deploy Boards Kubernetes Label](img/deploy_boards_kubernetes_label.png)
Once all of the above are set up and the pipeline has run at least once,
navigate to the environments page under **Operations > Environments**.
diff --git a/doc/user/project/deploy_tokens/index.md b/doc/user/project/deploy_tokens/index.md
index 72594733cd3..164d1dddff0 100644
--- a/doc/user/project/deploy_tokens/index.md
+++ b/doc/user/project/deploy_tokens/index.md
@@ -56,9 +56,9 @@ To download a repository using a Deploy Token, you just need to:
1. Take note of your `username` and `token`.
1. `git clone` the project using the Deploy Token:
- ```sh
- git clone http://<username>:<deploy_token>@gitlab.example.com/tanuki/awesome_project.git
- ```
+ ```sh
+ git clone http://<username>:<deploy_token>@gitlab.example.com/tanuki/awesome_project.git
+ ```
Replace `<username>` and `<deploy_token>` with the proper values.
diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md
index d51a0c0ccca..e4eb1a9a392 100644
--- a/doc/user/project/import/bitbucket_server.md
+++ b/doc/user/project/import/bitbucket_server.md
@@ -24,9 +24,8 @@ Import your projects from Bitbucket Server to GitLab with minimal effort.
1. Currently GitLab doesn't allow comments on arbitrary lines of code, so any
Bitbucket comments out of bounds will be inserted as comments in the merge
request.
-1. Bitbucket Server allows multiple levels of threading. GitLab
- import will collapse this into one discussion and quote part of the original
- comment.
+1. Bitbucket Server allows multiple levels of threading. GitLab import
+ will collapse this into one thread and quote part of the original comment.
1. Declined pull requests have unreachable commits, which prevents the GitLab
importer from generating a proper diff. These pull requests will show up as
empty changes.
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index 334be713aa5..9d7463416d8 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -34,7 +34,7 @@ This approach assumes all users from the self-hosted instance have already been
If the users haven't been migrated yet, the user conducting the import
will take the place of all references to the missing user(s).
-If you need to migrate all data over, you can leverage our [api](../../../api/README.md) to migrate from self-hosted to GitLab.com.
+If you need to migrate all data over, you can leverage our [api](../../../api/README.md) to migrate from self-hosted to GitLab.com.
The order of assets to migrate from a self-hosted instance to GitLab is the following:
1. [Users](../../../api/users.md)
@@ -54,5 +54,5 @@ perhaps from an old server to a new server for example, is to
[back up the project](../../../raketasks/backup_restore.md),
then restore it on the new server.
-In the event of merging two GitLab instances together (for example, both instances have existing data on them and one can't be wiped),
+In the event of merging two GitLab instances together (for example, both instances have existing data on them and one can't be wiped),
refer to the instructions in [Migrating from self-hosted GitLab to GitLab.com](#migrating-from-self-hosted-gitlab-to-gitlabcom).
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index f332281fa82..0ffa69b6b78 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -221,7 +221,7 @@ There are numerous [APIs](../../api/README.md) to use with your projects:
- [Badges](../../api/project_badges.md)
- [Clusters](../../api/project_clusters.md)
-- [Discussions](../../api/discussions.md)
+- [Threads](../../api/discussions.md)
- [General](../../api/projects.md)
- [Import/export](../../api/project_import_export.md)
- [Issue Board](../../api/boards.md)
diff --git a/doc/user/project/integrations/custom_issue_tracker.md b/doc/user/project/integrations/custom_issue_tracker.md
index 23f1ce7a15a..7c7263704f9 100644
--- a/doc/user/project/integrations/custom_issue_tracker.md
+++ b/doc/user/project/integrations/custom_issue_tracker.md
@@ -17,6 +17,6 @@ Once you have configured and enabled Custom Issue Tracker Service you'll see a l
## Referencing issues
-- Issues are referenced with `ANYTHING-<ID>`, where `ANYTHING` can be any string and `<ID>` is a number used in the target project of the custom integration (example `PROJECT-143`).
+- Issues are referenced with `ANYTHING-<ID>`, where `ANYTHING` can be any string and `<ID>` is a number used in the target project of the custom integration (example `PROJECT-143`).
- `ANYTHING` is a placeholder to differentiate against GitLab issues, which are referenced with `#<ID>`. You can use a project name or project key to replace it for example.
-- So with the example above, `PROJECT-143` would refer to `https://customissuetracker.com/project-name/143`. \ No newline at end of file
+- So with the example above, `PROJECT-143` would refer to `https://customissuetracker.com/project-name/143`.
diff --git a/doc/user/project/integrations/gitlab_slack_application.md b/doc/user/project/integrations/gitlab_slack_application.md
index 8e062ca627b..91de64be1fa 100644
--- a/doc/user/project/integrations/gitlab_slack_application.md
+++ b/doc/user/project/integrations/gitlab_slack_application.md
@@ -1,4 +1,4 @@
-# GitLab Slack application **[FREE ONLY]**
+# GitLab Slack application **(FREE ONLY)**
NOTE: **Note:**
The GitLab Slack application is only configurable for GitLab.com. It will **not**
diff --git a/doc/user/project/integrations/jira_server_configuration.md b/doc/user/project/integrations/jira_server_configuration.md
index 32991714973..5116cbfe9ac 100644
--- a/doc/user/project/integrations/jira_server_configuration.md
+++ b/doc/user/project/integrations/jira_server_configuration.md
@@ -13,46 +13,46 @@ access to your Jira projects. This is covered in the process below.
1. Log in to your Jira instance as an administrator and under **Jira Administration**
go to **User Management** to create a new user.
- ![Jira user management link](img/jira_user_management_link.png)
+ ![Jira user management link](img/jira_user_management_link.png)
1. The next step is to create a new user (e.g., `gitlab`) who has write access
to projects in Jira. Enter the user's name and a _valid_ e-mail address
since Jira sends a verification e-mail to set up the password.
_**Note:** Jira creates the username automatically by using the e-mail
prefix. You can change it later, if needed. Our integration does not support SSO (such as SAML). You will need to create
- an HTTP basic authentication password. You can do this by visiting the user
- profile, looking up the username, and setting a password._
+ an HTTP basic authentication password. You can do this by visiting the user
+ profile, looking up the username, and setting a password._
- ![Jira create new user](img/jira_create_new_user.png)
+ ![Jira create new user](img/jira_create_new_user.png)
1. Create a `gitlab-developers` group. (We will give this group write access to Jira
projects in a later step). Go to the **Groups** tab on the left, and select **Add group**.
- ![Jira create new user](img/jira_create_new_group.png)
+ ![Jira create new user](img/jira_create_new_group.png)
- Give it a name and click **Add group**.
+ Give it a name and click **Add group**.
1. Add the `gitlab` user to the `gitlab-developers` group by clicking **Edit members**.
The `gitlab-developers` group should be listed in the leftmost box as a selected group.
Under **Add members to selected group(s)**, enter `gitlab`.
- ![Jira add user to group](img/jira_add_user_to_group.png)
-
+ ![Jira add user to group](img/jira_add_user_to_group.png)
+
Click **Add selected users** and `gitlab` should appear in the **Group member(s)** box.
This membership is saved automatically.
-
- ![Jira added user to group](img/jira_added_user_to_group.png)
+
+ ![Jira added user to group](img/jira_added_user_to_group.png)
1. To give the newly-created group 'write' access, you need to create a **Permission Scheme**.
To do this, click the gear icon and select **Issues**. Then click **Permission Schemes**.
Click **Add Permission Scheme** and enter a **Name** and, optionally, a **Description**.
-
+
1. Once your permission scheme is created, you'll be taken back to the permissions scheme list.
- Locate your new permissions scheme and click **Permissions**. Next to **Administer Projects**,
+ Locate your new permissions scheme and click **Permissions**. Next to **Administer Projects**,
click **Edit**. In the resulting dialog box, select **Group** and select `gitlab-developers`
from the dropdown.
- ![Jira group access](img/jira_group_access.png)
+ ![Jira group access](img/jira_group_access.png)
The Jira configuration is complete. Write down the new Jira username and its
password as they will be needed when [configuring GitLab in the next section](jira.md#configuring-gitlab).
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index 62e08a183f7..67274e8d924 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -20,10 +20,10 @@ Below, you will find a list of the currently supported ones accompanied with com
Click on the service links to see further configuration instructions and details.
-| Service | Description |
+| Service | Description |
| ------- | ----------- |
-| Asana | Asana - Teamwork without email |
-| Assembla | Project Management Software (Source Commits Endpoint) |
+| Asana | Asana - Teamwork without email |
+| Assembla | Project Management Software (Source Commits Endpoint) |
| [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server |
| Buildkite | Continuous integration and deployments |
| [Bugzilla](bugzilla.md) | Bugzilla issue tracker |
@@ -48,7 +48,7 @@ Click on the service links to see further configuration instructions and details
| Pipelines emails | Email the pipeline status to a list of recipients |
| [Slack Notifications](slack.md) | Send GitLab events (e.g. issue created) to Slack as notifications |
| [Slack slash commands](slack_slash_commands.md) **(CORE ONLY)** | Use slash commands in Slack to control GitLab |
-| [GitLab Slack application](gitlab_slack_application.md) **[FREE ONLY]** | Use Slack's official application |
+| [GitLab Slack application](gitlab_slack_application.md) **(FREE ONLY)** | Use Slack's official application |
| PivotalTracker | Project Management Software (Source Commits Endpoint) |
| [Prometheus](prometheus.md) | Monitor the performance of your deployed apps |
| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop |
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index 765aa91b00f..72f12972596 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -121,70 +121,93 @@ GitLab supports a limited set of [CI variables](../../../ci/variables/README.htm
To specify a variable in a query, enclose it in curly braces with a leading percent. For example: `%{ci_environment_slug}`.
-### Defining Dashboards for Prometheus Metrics per Project
+### Defining custom dashboards per project
-All projects include a GitLab-defined system dashboard, which includes a few key metrics. Optionally, additional dashboards can also be defined by including configuration files in the project repository under `.gitlab/dashboards`. Configuration files nested under subdirectories will not be available in the UI. Each file should define the layout of the dashboard and the prometheus queries used to populate data. Dashboards can be selected from the dropdown in the UI.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/59974) in GitLab 12.1.
-#### Relationship to Custom Metrics
+By default, all projects include a GitLab-defined Prometheus dashboard, which
+includes a few key metrics, but you can also define your own custom dashboards.
-[Custom Metrics](#adding-additional-metrics-premium) are defined through the UI and, at this point, are unique from metrics defined in dashboard configuration files. Custom Metrics will appear on the system dashboard, as well as support alerting, whereas metrics defined in configuration files do not yet support alerts.
+NOTE: **Note:**
+The custom metrics as defined below do not support alerts, unlike
+[additional metrics](#adding-additional-metrics-premium).
-#### Dashboard Configuration
+Dashboards have several components:
-Dashboards have several components. A dashboard has many panel groups, which are comprised of panels, which support one or more metrics. The dashboard should be saved with the `.yml` extension.
+- Panel groups, which comprise panels.
+- Panels, which support one or more metrics.
-Sample YML Configuration
-```
-dashboard: 'Dashboard Title'
-priority: 2
-panel_groups:
- - group: 'Group Title'
- panels:
- - type: area-chart
- title: "Chart Title"
- y_label: "Y-Axis"
- metrics:
- - id: metric_of_ages
- query_range: 'http_requests_total'
- label: "Metric of Ages"
- unit: "count"
-```
+To configure a custom dashboard:
+
+1. Create a YAML file with the `.yml` extension under your repository's root
+ directory inside `.gitlab/dashboards/`. For example, create
+ `.gitlab/dashboards/prom_alerts.yml` with the following contents:
+
+ ```yaml
+ dashboard: 'Dashboard Title'
+ panel_groups:
+ - group: 'Group Title'
+ panels:
+ - type: area-chart
+ title: "Chart Title"
+ y_label: "Y-Axis"
+ metrics:
+ - id: metric_of_ages
+ query_range: 'http_requests_total'
+ label: "Metric of Ages"
+ unit: "count"
+ ```
+
+ The above sample dashboard would display a single area chart. Each file should
+ define the layout of the dashboard and the Prometheus queries used to populate
+ data.
+
+1. Save the file, commit, and push to your repository.
+1. Navigate to your project's **Operations > Metrics** and choose the custom
+ dashboard from the dropdown.
+
+NOTE: **Note:**
+Configuration files nested under subdirectories of `.gitlab/dashboards` are not
+supported and will not be available in the UI.
-The above sample dashboard would display a single area chart. The following sections outline the details of expected properties.
+The following tables outline the details of expected properties.
-##### Dashboard Properties
-| Property | Type | Required? | Meaning |
+**Dashboard properties:**
+
+| Property | Type | Required | Description |
| ------ | ------ | ------ | ------ |
-| `dashboard` | string | required | Heading for the dashboard. Only one dashboard should be defined per file. |
-| `priority` | number | optional, default to definition order | Order to appear in dashboard dropdown, higher priority should be higher in the dropdown. Numbers do not need to be consecutive. |
-| `panel_groups` | array | required | The panel groups which should be on the dashboard. |
+| `dashboard` | string | yes | Heading for the dashboard. Only one dashboard should be defined per file. |
+| `panel_groups` | array | yes | The panel groups which should be on the dashboard. |
+
+**Panel group (`panel_groups`) properties:**
-##### Panel Group Properties
-| Property | Type | Required? | Meaning |
+| Property | Type | Required | Description |
| ------ | ------ | ------ | ------ |
| `group` | string | required | Heading for the panel group. |
-| `priority` | number | optional, defaults to order in file | Order to appear on the dashboard, higher priority will be higher on the page. Numbers do not need to be consecutive. |
+| `priority` | number | optional, defaults to order in file | Order to appear on the dashboard. Higher number means higher priority, which will be higher on the page. Numbers do not need to be consecutive. |
| `panels` | array | required | The panels which should be in the panel group. |
-##### Panel Properties
-| Property | Type | Required? | Meaning |
+**Panel (`panels`) properties:**
+
+| Property | Type | Required | Description |
| ------ | ------ | ------ | ------- |
-| `type` | enum | optional, defaults to `area-chart` | Specifies the chart type to use. Only `area-chart` is currently supported. |
-| `title` | string | required | Heading for the panel. |
-| `y_label` | string | optional, but highly encouraged | Y-Axis label for the panel. |
-| `weight` | number | optional, defaults to order in file | Order to appear within the grouping, higher priority will be higher on the page. Numbers do not need to be consecutive. |
-| `metrics` | array | required | The metrics which should be displayed in the panel. |
-
-##### Metric Properties
-| Property | Type | Required? | Meaning |
+| `type` | enum | no, defaults to `area-chart` | Specifies the chart type to use. Only `area-chart` is currently supported. |
+| `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. |
+| `metrics` | array | yes | The metrics which should be displayed in the panel. |
+
+**Metrics (`metrics`) properties:**
+
+| Property | Type | Required | Description |
| ------ | ------ | ------ | ------ |
-| `id` | string | optional | Used for associating dashboard metrics with database records. Must be unique across dashboard configuration files. Required for [alerting](#setting-up-alerts-for-prometheus-metrics-ultimate) (support not yet enabled, see [relevant issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/60319)). |
-| `unit` | string | required | Defines the unit of the query's return data. |
-| `label` | string | optional, but highly encouraged | Defines the legend-label for the query. Should be unique within the panel's metrics. |
-| `query` | string | required unless `query_range` is defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
-| `query_range` | string | required unless `query` is defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query_range` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
+| `id` | string | no | Used for associating dashboard metrics with database records. Must be unique across dashboard configuration files. Required for [alerting](#setting-up-alerts-for-prometheus-metrics-ultimate) (support not yet enabled, see [relevant issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/60319)). |
+| `unit` | string | yes | Defines the unit of the query's return data. |
+| `label` | string | no, but highly encouraged | Defines the legend-label for the query. Should be unique within the panel's metrics. |
+| `query` | string | yes if `query_range` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
+| `query_range` | string | yes if `query` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query_range` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
-### Setting up alerts for Prometheus metrics **[ULTIMATE]**
+### Setting up alerts for Prometheus metrics **(ULTIMATE)**
#### Managed Prometheus instances
@@ -232,7 +255,17 @@ Alerts can be used to trigger actions, like open an issue automatically (enabled
1. Optionally, select whether to send an email notification to the developers of the project.
1. Click **Save changes**.
-Once enabled, an issue will be opened automatically when an alert is triggered. The author of the issue will be the GitLab Alert Bot. To further customize the issue, you can add labels, mentions, or any other supported [quick action](../quick_actions.md) in the selected issue template.
+Once enabled, an issue will be opened automatically when an alert is triggered which contains values extracted from [alert's payload](https://prometheus.io/docs/alerting/configuration/#webhook_config
+):
+
+- Issue author: `GitLab Alert Bot`
+- Issue title: Extract from `annotations/title`, `annotations/summary` or `labels/alertname`
+- Alert `Summary`: A list of properties
+ - `starts_at`: Alert start time via `startsAt`
+ - `full_query`: Alert query extracted from `generatorURL`
+ - Optional list of attached annotations extracted from `annotations/*`
+
+To further customize the issue, you can add labels, mentions, or any other supported [quick action](../quick_actions.md) in the selected issue template.
If the metric exceeds the threshold of the alert for over 5 minutes, an email will be sent to all [Maintainers and Owners](../../permissions.md#project-members-permissions) of the project.
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
index 0d300d3c418..9e17edf7d36 100644
--- a/doc/user/project/integrations/prometheus_library/kubernetes.md
+++ b/doc/user/project/integrations/prometheus_library/kubernetes.md
@@ -13,15 +13,15 @@ integration services must be enabled.
- Average Memory Usage (MB):
- ```
- avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024
- ```
+ ```
+ avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024
+ ```
- Average CPU Utilization (%):
- ```
- avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))
- ```
+ ```
+ avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))
+ ```
## Configuring Prometheus to monitor for Kubernetes metrics
@@ -48,12 +48,12 @@ These metrics expect the [Deployment](https://kubernetes.io/docs/concepts/worklo
- Average Memory Usage (MB)
- ```
- avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024
- ```
+ ```
+ avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024
+ ```
- Average CPU Utilization (%)
- ```
- avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))
- ```
+ ```
+ avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))
+ ```
diff --git a/doc/user/project/issues/crosslinking_issues.md b/doc/user/project/issues/crosslinking_issues.md
index 93dc2a2e4ca..ec9eb7b62bb 100644
--- a/doc/user/project/issues/crosslinking_issues.md
+++ b/doc/user/project/issues/crosslinking_issues.md
@@ -47,7 +47,7 @@ display in both issues. The same is valid when mentioning issues in [merge reque
## From Merge Requests
Mentioning issues in merge request comments works exactly the same way as
-they do for [related issues](#from-related-issues).
+they do for [related issues](#from-related-issues).
When you mention an issue in a merge request description, it will simply
[link the issue and merge request together](#from-related-issues). Additionally,
diff --git a/doc/user/project/issues/csv_export.md b/doc/user/project/issues/csv_export.md
index 0b7a7af5927..d3f53c09fb3 100644
--- a/doc/user/project/issues/csv_export.md
+++ b/doc/user/project/issues/csv_export.md
@@ -48,7 +48,6 @@ Exported issues are always sorted by `Issue ID`.
Data will be encoded with a comma as the column delimiter, with `"` used to quote fields if needed, and newlines to separate rows. The first row will be the headers, which are listed in the following table along with a description of the values:
-
| Column | Description |
|---------|-------------|
| Issue ID | Issue `iid` |
@@ -71,7 +70,6 @@ Data will be encoded with a comma as the column delimiter, with `"` used to quot
| Time Estimate | [Time estimate](../../../workflow/time_tracking.md#estimates) in seconds |
| Time Spent | [Time spent](../../../workflow/time_tracking.md#time-spent) in seconds |
-
## Limitations
As the issues will be sent as an email attachment, there is a limit on how much data can be exported. Currently this limit is 20MB to ensure successful delivery across a range of email providers. If this limit is reached we suggest narrowing the search before export, perhaps by exporting open and closed issues separately.
diff --git a/doc/user/project/issues/issue_data_and_actions.md b/doc/user/project/issues/issue_data_and_actions.md
index 9c4d0de46d3..7b031f83cb1 100644
--- a/doc/user/project/issues/issue_data_and_actions.md
+++ b/doc/user/project/issues/issue_data_and_actions.md
@@ -116,13 +116,13 @@ issue boards or the issue list.
#### 11. Lock issue
-You can [lock the discussions](../../discussions/index.md#lock-discussions) in the issue,
+You can [lock the threads](../../discussions/index.md#lock-discussions) in the issue,
to prevent further comments from being added.
#### 12. Participants
-All the users involved in that issue. Either they participated in the [discussion](../../discussions/index.md),
-or were mentioned in the description or discussions.
+All the users involved in that issue. Either they participated in the [thread](../../discussions/index.md),
+or were mentioned in the description or threads.
#### 13. Notifications
@@ -187,8 +187,8 @@ You can also click the `+` to add more related issues.
#### 19. Related Merge Requests
-Merge requests that were mentioned in that issue's description or in the issue discussion
-thread are listed as [related merge requests](crosslinking_issues.md#from-merge-requests) here.
+Merge requests that were mentioned in that issue's description or in the issue thread
+are listed as [related merge requests](crosslinking_issues.md#from-merge-requests) here.
Also, if the current issue was mentioned as related in another merge request, that
merge request will be listed here.
@@ -200,17 +200,17 @@ dropdown list of available [GitLab Flavored Markdown Emoji](../../markdown.md#em
TIP: **Tip:**
Posting "+1" as a comment in a thread spams all subscribed participants of that issue,
-clutters the discussion threads, and is not recommended. Awarding an emoji is a way
+clutters the threads, and is not recommended. Awarding an emoji is a way
to let them know your reaction without spamming them.
#### 21. Show all activity
You can filter what is displayed in the issue history by clicking on **Show all activity**
-and selecting either **Show comments only**, which only shows discussions and hides
-updates to the issue, or **Show history only**, which hides discussions and only shows updates.
+and selecting either **Show comments only**, which only shows threads and hides
+updates to the issue, or **Show history only**, which hides threads and only shows updates.
- You can mention a user or a group present in your GitLab instance with
- `@username` or `@groupname` and they will be notified via To-Do items
+ `@username` or `@groupname` and they will be notified via To-Do items
and email, unless they have [disabled all notifications](#13-notifications)
in their profile settings.
- Mentions for yourself (the current logged in user), will be highlighted
@@ -242,15 +242,15 @@ filtered, as shown above.
Collaborate in the issue by posting comments in its thread. This text field also fully
supports [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm).
-#### 25. Submit Comment, start a discussion, or comment and close
+#### 25. Submit Comment, start a thread, or comment and close
Once you write a comment, you can:
- Click **Comment** and your comment will be published.
-- Choose **Start discussion** from the dropdown list and start a new [discussion thread](../../discussions/index.md#threaded-discussions)
+- Choose **Start thread** from the dropdown list and start a new [thread](../../discussions/index.md#threaded-discussions)
within that issue's main thread to discuss specific points. This invites other participants
- to reply directly to your discussion, keeping related comments grouped together.
+ to reply directly to your thread, keeping related comments grouped together.
-![Comment or discussion](img/comment-or-discussion.png)
+![Comment or thread](img/comment-or-discussion.png)
You can also close the issue from here, so you don't need to scroll to the top of the issue page.
diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md
index 2a490e3fd7f..e343fd45488 100644
--- a/doc/user/project/members/index.md
+++ b/doc/user/project/members/index.md
@@ -10,8 +10,6 @@ or import a new user to your project.
To view, edit, add, and remove project's members, go to your
project's **Settings > Members**.
----
-
## Add a user
Right next to **People**, start typing the name or username of the user you
@@ -19,22 +17,16 @@ want to add.
![Search for people](img/add_user_search_people.png)
----
-
Select the user and the [permission level](../../permissions.md)
that you'd like to give the user. Note that you can select more than one user.
![Give user permissions](img/add_user_give_permissions.png)
----
-
Once done, hit **Add users to project** and they will be immediately added to
your project with the permissions you gave them above.
![List members](img/add_user_list_members.png)
----
-
From there on, you can either remove an existing user or change their access
level to the project.
@@ -47,8 +39,6 @@ In the dropdown menu, you can see only the projects you are Maintainer on.
![Import members from another project](img/add_user_import_members_from_another_project.png)
----
-
Select the one you want and hit **Import project members**. A flash message
notifying you that the import was successful will appear, and the new members
are now in the project's members list. Notice that the permissions that they
@@ -56,8 +46,6 @@ had on the project you imported from are retained.
![Members list of new members](img/add_user_imported_members.png)
----
-
## Invite people using their e-mail address
If a user you want to give access to doesn't have an account on your GitLab
@@ -66,23 +54,17 @@ user search field.
![Invite user by mail](img/add_user_email_search.png)
----
-
As you can imagine, you can mix inviting multiple people and adding existing
GitLab users to the project.
![Invite user by mail ready to submit](img/add_user_email_ready.png)
----
-
Once done, hit **Add users to project** and watch that there is a new member
with the e-mail address we used above. From there on, you can resend the
invitation, change their access level, or even delete them.
![Invite user members list](img/add_user_email_accept.png)
----
-
Once the user accepts the invitation, they will be prompted to create a new
GitLab account using the same e-mail address the invitation was sent to.
@@ -97,15 +79,11 @@ side of your screen.
![Request access button](img/request_access_button.png)
----
-
Project owners & maintainers will be notified of your request and will be able to approve or
decline it on the members page.
![Manage access requests](img/access_requests_management.png)
----
-
If you change your mind before your request is approved, just click the
**Withdraw Access Request** button.
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index c299a8ecb96..f593046fa8b 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -18,7 +18,7 @@ It is as simple as the name implies: a _request_ to _merge_ one branch into anot
With GitLab merge requests, you can:
- Compare the changes between two [branches](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell#_git_branching)
-- [Review and discuss](../../discussions/index.md#discussions) the proposed modifications inline
+- [Review and discuss](../../discussions/index.md#threads) the proposed modifications inline
- Live preview the changes when [Review Apps](../../../ci/review_apps/index.md) is configured for your project
- Build, test, and deploy your code in a per-branch basis with built-in [GitLab CI/CD](../../../ci/README.md)
- Prevent the merge request from being merged before it's ready with [WIP MRs](#work-in-progress-merge-requests)
@@ -155,13 +155,13 @@ and remember to merge the request manually.
[Learn more about merging when pipeline succeeds.](merge_when_pipeline_succeeds.md)
-## Resolve discussion comments in merge requests reviews
+## Resolve threads in merge requests reviews
Keep track of the progress during a code review with resolving comments.
Resolving comments prevents you from forgetting to address feedback and lets
-you hide discussions that are no longer relevant.
+you hide threads that are no longer relevant.
-[Read more about resolving discussion comments in merge requests reviews.](../../discussions/index.md)
+[Read more about resolving threads in merge requests reviews.](../../discussions/index.md)
## Commenting on any file line in merge requests
@@ -192,7 +192,7 @@ commit when merging, to allow for a neater commit history.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/18008) in GitLab 11.6.
As a reviewer, you can add suggestions to change the content in
-merge request discussions, and users with appropriate [permission](../../permissions.md)
+merge request threads, and users with appropriate [permission](../../permissions.md)
can easily apply them to the codebase directly from the UI. Read
through the documentation on [Suggest changes](../../discussions/index.md#suggest-changes)
to learn more.
diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md
index 0f392676316..220795d6f15 100644
--- a/doc/user/project/merge_requests/merge_request_approvals.md
+++ b/doc/user/project/merge_requests/merge_request_approvals.md
@@ -162,7 +162,7 @@ the merge request is unblocked and can be merged.
Note, that meeting the required number of approvals is a necessary, but not
sufficient condition for unblocking a merge request from being merged. There
are other conditions that may block it, such as merge conflicts,
-[pending discussions](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-discussions-are-resolved)
+[pending discussions](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-threads-are-resolved)
or a [failed CI/CD pipeline](merge_when_pipeline_succeeds.md).
## Code Owners approvals **(PREMIUM)**
diff --git a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
index 0dd60d84c42..50a4e514d49 100644
--- a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
+++ b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
@@ -36,7 +36,7 @@ changes to be reviewed.
## Only allow merge requests to be merged if the pipeline succeeds
You can prevent merge requests from being merged if their pipeline did not succeed
-or if there are discussions to be resolved.
+or if there are threads to be resolved.
Navigate to your project's settings page and expand the **Merge requests** section.
In the **Merge checks** subsection, select the **Pipelines must succeed** check
diff --git a/doc/user/project/merge_requests/work_in_progress_merge_requests.md b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
index 142178ba241..ea59644fce6 100644
--- a/doc/user/project/merge_requests/work_in_progress_merge_requests.md
+++ b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
@@ -5,7 +5,7 @@ type: reference, concepts
# "Work In Progress" merge requests
If a merge request is not yet ready to be merged, perhaps due to continued development
-or open discussions, you can prevent it from being accepted before it's ready by flagging
+or open threads, you can prevent it from being accepted before it's ready by flagging
it as a **Work In Progress**. This will disable the "Merge" button, preventing it from
being merged, and it will stay disabled until the "WIP" flag has been removed.
@@ -19,7 +19,7 @@ There are several ways to flag a merge request as a Work In Progress:
**Start the title with WIP:**, under the title box, when editing the merge request's
description will have the same effect.
- Add the `/wip` [quick action](../quick_actions.md#quick-actions-for-issues-and-merge-requests)
- in a discussion comment in the merge request. This is a toggle, and can be repeated
+ in a comment in the merge request. This is a toggle, and can be repeated
to change the status back. Note that any other text in the comment will be discarded.
- Add "wip" or "WIP" to the start of a commit message targeting the merge request's
source branch. This is not a toggle, and doing it again in another commit will have
@@ -34,7 +34,7 @@ Similar to above, when a Merge Request is ready to be merged, you can remove the
**Remove the WIP: prefix from the title**, under the title box, when editing the merge
request's description, will have the same effect.
- Add the `/wip` [quick action](../quick_actions.md#quick-actions-for-issues-and-merge-requests)
- in a discussion comment in the merge request. This is a toggle, and can be repeated
+ in a comment in the merge request. This is a toggle, and can be repeated
to change the status back. Note that any other text in the comment will be discarded.
- Click on the **Resolve WIP status** button near the bottom of the merge request description,
next to the "Merge" button (see [image above](#work-in-progress-merge-requests)).
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index b0745b1e2c5..142462e1879 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -14,12 +14,12 @@ the start and end of your Agile sprint.
Set the milestone title to the name of your Agile sprint,
such as `November 2018 sprint`.
Add an issue to your Agile sprint by associating
-the milestone to the issue.
+the milestone to the issue.
## Milestones as releases
Milestones can be used as releases.
-Set the milestone due date to represent the release date of your release.
+Set the milestone due date to represent the release date of your release.
(And leave the milestone start date blank.)
Set the milestone title to the version of your release,
such as `Version 9.4`.
diff --git a/doc/user/project/new_ci_build_permissions_model.md b/doc/user/project/new_ci_build_permissions_model.md
index d35a8568394..494dd539da7 100644
--- a/doc/user/project/new_ci_build_permissions_model.md
+++ b/doc/user/project/new_ci_build_permissions_model.md
@@ -6,8 +6,6 @@ GitLab 8.12 has a completely redesigned [job permissions] system. You can find
all discussion and all our concerns when choosing the current approach in issue
[#18994](https://gitlab.com/gitlab-org/gitlab-ce/issues/18994).
----
-
Jobs permissions should be tightly integrated with the permissions of a user
who is triggering a job.
@@ -108,8 +106,6 @@ and to checkout project sources.
It could also be used with the GitLab Container Registry for that project,
allowing pulling and pushing Docker images from within the CI job.
----
-
GitLab would create a special checkout URL like:
```
diff --git a/doc/user/project/packages/maven_repository.md b/doc/user/project/packages/maven_repository.md
index 27c052fb2bc..c61402afb2c 100644
--- a/doc/user/project/packages/maven_repository.md
+++ b/doc/user/project/packages/maven_repository.md
@@ -198,7 +198,7 @@ domain name.
NOTE: **Note:**
For retrieving artifacts, you can use either the
[URL encoded](../../../api/README.md#namespaced-path-encoding) path of the group
-(e.g., `group%2Fsubgroup`) or the group's ID (e.g., `12`).
+(e.g., `group%2Fsubgroup`) or the group's ID (e.g., `12`).
### Instance level Maven endpoint
@@ -279,59 +279,59 @@ shows how to create a new package each time the `master` branch is updated:
Add the server section with the same id you defined in your `pom.xml` file.
For example, in our case it's `gitlab-maven`:
- ```xml
- <settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
- <servers>
- <server>
- <id>gitlab-maven</id>
- <configuration>
- <httpHeaders>
- <property>
- <name>Job-Token</name>
- <value>${env.CI_JOB_TOKEN}</value>
- </property>
- </httpHeaders>
- </configuration>
- </server>
- </servers>
- </settings>
- ```
+ ```xml
+ <settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
+ <servers>
+ <server>
+ <id>gitlab-maven</id>
+ <configuration>
+ <httpHeaders>
+ <property>
+ <name>Job-Token</name>
+ <value>${env.CI_JOB_TOKEN}</value>
+ </property>
+ </httpHeaders>
+ </configuration>
+ </server>
+ </servers>
+ </settings>
+ ```
1. Make sure your `pom.xml` file includes the following:
- ```xml
- <repositories>
- <repository>
- <id>gitlab-maven</id>
- <url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
- </repository>
- </repositories>
- <distributionManagement>
- <repository>
- <id>gitlab-maven</id>
- <url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
- </repository>
- <snapshotRepository>
- <id>gitlab-maven</id>
- <url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
- </snapshotRepository>
- </distributionManagement>
- ```
-
- TIP: **Tip:**
- You can either let Maven utilize the CI environment variables or hardcode your project's ID.
+ ```xml
+ <repositories>
+ <repository>
+ <id>gitlab-maven</id>
+ <url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
+ </repository>
+ </repositories>
+ <distributionManagement>
+ <repository>
+ <id>gitlab-maven</id>
+ <url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
+ </repository>
+ <snapshotRepository>
+ <id>gitlab-maven</id>
+ <url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
+ </snapshotRepository>
+ </distributionManagement>
+ ```
+
+ TIP: **Tip:**
+ You can either let Maven utilize the CI environment variables or hardcode your project's ID.
1. Add a `deploy` job to your `.gitlab-ci.yml` file:
- ```yaml
- deploy:
- image: maven:3.3.9-jdk-8
- script:
- - 'mvn deploy -s ci_settings.xml'
- only:
- - master
- ```
+ ```yaml
+ deploy:
+ image: maven:3.3.9-jdk-8
+ script:
+ - 'mvn deploy -s ci_settings.xml'
+ only:
+ - master
+ ```
1. Push those files to your repository.
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
new file mode 100644
index 00000000000..3b80370d4a9
--- /dev/null
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
@@ -0,0 +1,95 @@
+---
+type: concepts
+---
+
+# DNS records overview
+
+_Read this document for a brief overview of DNS records in the scope
+of GitLab Pages, for beginners in web development._
+
+A Domain Name System (DNS) web service routes visitors to websites
+by translating domain names (such as `www.example.com`) into the
+numeric IP addresses (such as `192.0.2.1`) that computers use to
+connect to each other.
+
+A DNS record is created to point a (sub)domain to a certain location,
+which can be an IP address or another domain. In case you want to use
+GitLab Pages with your own (sub)domain, you need to access your domain's
+registrar control panel to add a DNS record pointing it back to your
+GitLab Pages site.
+
+Note that **how to** add DNS records depends on which server your domain
+is hosted on. Every control panel has its own place to do it. If you are
+not an admin of your domain, and don't have access to your registrar,
+you'll need to ask for the technical support of your hosting service
+to do it for you.
+
+To help you out, we've gathered some instructions on how to do that
+for the most popular hosting services:
+
+- [Amazon](http://docs.aws.amazon.com/gettingstarted/latest/swh/getting-started-configure-route53.html)
+- [Bluehost](https://my.bluehost.com/cgi/help/559)
+- [CloudFlare](https://support.cloudflare.com/hc/en-us/articles/200169096-How-do-I-add-A-records-)
+- [cPanel](https://documentation.cpanel.net/display/ALD/Edit+DNS+Zone)
+- [DreamHost](https://help.dreamhost.com/hc/en-us/articles/215414867-How-do-I-add-custom-DNS-records-)
+- [Go Daddy](https://www.godaddy.com/help/add-an-a-record-19238)
+- [Hostgator](http://support.hostgator.com/articles/changing-dns-records)
+- [Inmotion hosting](https://my.bluehost.com/cgi/help/559)
+- [Media Temple](https://mediatemple.net/community/products/dv/204403794/how-can-i-change-the-dns-records-for-my-domain)
+- [Microsoft](https://msdn.microsoft.com/en-us/library/bb727018.aspx)
+
+If your hosting service is not listed above, you can just try to
+search the web for `how to add dns record on <my hosting service>`.
+
+## `A` record
+
+A DNS A record maps a host to an IPv4 IP address.
+It points a root domain as `example.com` to the host's IP address as
+`192.192.192.192`.
+
+Example:
+
+- `example.com` => `A` => `192.192.192.192`
+
+## CNAME record
+
+CNAME records define an alias for canonical name for your server (one defined
+by an A record). It points a subdomain to another domain.
+
+Example:
+
+- `www` => `CNAME` => `example.com`
+
+This way, visitors visiting `www.example.com` will be redirected to
+`example.com`.
+
+## MX record
+
+MX records are used to define the mail exchanges that are used for the domain.
+This helps email messages arrive at your mail server correctly.
+
+Example:
+
+- `MX` => `mail.example.com`
+
+Then you can register emails for `users@mail.example.com`.
+
+## TXT record
+
+A `TXT` record can associate arbitrary text with a host or other name. A common
+use is for site verification.
+
+Example:
+
+- `example.com`=> TXT => `"google-site-verification=6P08Ow5E-8Q0m6vQ7FMAqAYIDprkVV8fUf_7hZ4Qvc8"`
+
+This way, you can verify the ownership for that domain name.
+
+## All combined
+
+You can have one DNS record or more than one combined:
+
+- `example.com` => `A` => `192.192.192.192`
+- `www` => `CNAME` => `example.com`
+- `MX` => `mail.example.com`
+- `example.com`=> TXT => `"google-site-verification=6P08Ow5E-8Q0m6vQ7FMAqAYIDprkVV8fUf_7hZ4Qvc8"` \ No newline at end of file
diff --git a/doc/user/project/pages/img/add_certificate_to_pages.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/add_certificate_to_pages.png
index d92a981dc60..d92a981dc60 100644
--- a/doc/user/project/pages/img/add_certificate_to_pages.png
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/add_certificate_to_pages.png
Binary files differ
diff --git a/doc/user/project/pages/img/dns_add_new_a_record_example_updated_2018.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/dns_add_new_a_record_example_updated_2018.png
index 0150329d4b2..0150329d4b2 100644
--- a/doc/user/project/pages/img/dns_add_new_a_record_example_updated_2018.png
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/dns_add_new_a_record_example_updated_2018.png
Binary files differ
diff --git a/doc/user/project/pages/img/dns_cname_record_example.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/dns_cname_record_example.png
index 43d1a838544..43d1a838544 100644
--- a/doc/user/project/pages/img/dns_cname_record_example.png
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/dns_cname_record_example.png
Binary files differ
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.png
new file mode 100644
index 00000000000..b4dcdc9bb60
--- /dev/null
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.png
Binary files differ
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.png
new file mode 100644
index 00000000000..db8f25bc6c3
--- /dev/null
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.png
Binary files differ
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
new file mode 100644
index 00000000000..6c0d3e9e9d3
--- /dev/null
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
@@ -0,0 +1,257 @@
+---
+last_updated: 2019-07-04
+type: reference, howto
+redirect_from: 'https://docs.gitlab.com/ee/user/project/pages/getting_started_part_three.html'
+---
+
+# Custom domains and SSL/TLS Certificates
+
+Setting up GitLab Pages with custom domains, and adding SSL/TLS certificates to them, are optional features of GitLab Pages.
+
+To use one or more custom domain names with your Pages site, you can:
+
+- Add a [custom **root domain** or a **subdomain**](#set-up-pages-with-a-custom-domain).
+- Add [SSL/TLS certification](#adding-an-ssltls-certificate-to-pages).
+
+## Set up Pages with a custom domain
+
+To set up Pages with a custom domain name, read the requirements
+and steps below.
+
+### Requirements
+
+- A GitLab Pages website up and running, served under the default Pages domain
+ (`*.gitlab.io`, for GitLab.com).
+- A custom domain name `example.com` or subdomain `subdomain.example.com`.
+- Access to your domain's server control panel to set up DNS records:
+ - A DNS A or CNAME record poiting your domain to GitLab Pages server.
+ - A DNS TXT record to verify your domain's ownership.
+
+### Steps
+
+Follow the steps below to add your custom domain to Pages. See also
+this document for an [overview on DNS records](dns_concepts.md).
+
+#### 1. Add a custom domain to Pages
+
+Navigate to your project's **Setting > Pages** and click **+ New domain**
+to add your custom domain to GitLab Pages. You can choose whether to:
+
+- Add an [SSL/TLS certificate](#adding-an-ssltls-certificate-to-pages).
+- Leave it blank (it can be added later).
+
+Click **Create New Domain**.
+
+![Add new domain](img/add_certificate_to_pages.png)
+
+#### 2. Get the verification code
+
+Once you have added a new domain to Pages, the verification code will be prompted to you. Copy the values from GitLab and paste them in your domain's control panel as a TXT record on the next step.
+
+![Get the verification code](img/get_domain_verification_code_v12_0.png)
+
+#### 3. Set up DNS records for Pages
+
+Read this document for an [overview of DNS records for Pages](dns_concepts.md).
+If you're familiar with the subject, follow the instructions below
+according to the type of domain you want to use with your Pages site:
+
+- [For root domains](#for-root-domains), `example.com`.
+- [For subdomains](#for-subdomains), `subdomain.example.com`.
+- [For both](#for-both-root-and-subdomains).
+
+##### For root domains
+
+Root domains (`example.com`) require:
+
+- A [DNS A record](dns_concepts.md#a-record) pointing your domain to the Pages server.
+- A [TXT record](dns_concepts.md#txt-record) to verify your domain's ownership.
+
+| From | DNS Record | To |
+| ---- | ---------- | -- |
+| example.com | A | 35.185.44.232 |
+| _gitlab-pages-verification-code.example.com | TXT | gitlab-pages-verification-code=00112233445566778899aabbccddeeff |
+
+For projects on GitLab.com, this IP is `35.185.44.232`.
+For projects living in other GitLab instances (CE or EE), please contact
+your sysadmin asking for this information (which IP address is Pages
+server running on your instance).
+
+![DNS A record pointing to GitLab.com Pages server](img/dns_add_new_a_record_example_updated_2018.png)
+
+CAUTION: **Caution:**
+Note that if you use your root domain for your GitLab Pages website
+**only**, and if your domain registrar supports this feature, you can
+add a DNS apex `CNAME` record instead of an `A` record. The main
+advantage of doing so is that when GitLab Pages IP on GitLab.com
+changes for whatever reason, you don't need to update your `A` record.
+There may be a few exceptions, but **this method is not recommended**
+as it most likely won't work if you set an [`MX` record](dns_concepts.md#mx-record) for your root domain.
+
+##### For subdomains
+
+Subdomains (`subdomain.example.com`) require:
+
+- A DNS [CNAME record](dns_concepts.md#cname-record) record pointing your subdomain to the Pages server.
+- A DNS [TXT record](dns_concepts.md#txt-record) to verify your domain's ownership.
+
+| From | DNS Record | To |
+| ---- | ---------- | -- |
+| subdomain.example.com | CNAME | namespace.gitlab.io |
+| _gitlab-pages-verification-code.subdomain.example.com | TXT | gitlab-pages-verification-code=00112233445566778899aabbccddeeff |
+
+Note that, whether it's a user or a project website, the `CNAME`
+should point to your Pages domain (`namespace.gitlab.io`),
+without any `/project-name`.
+
+![DNS CNAME record pointing to GitLab.com project](img/dns_cname_record_example.png)
+
+##### For both root and subdomains
+
+There are a few cases where you need point both subdomain and root
+domain to the same website, for instance, `example.com` and `www.example.com`.
+
+They require:
+
+- A DNS A record for the domain.
+- A DNS CNAME record for the subdomain.
+- A DNS TXT record for each.
+
+| From | DNS Record | To |
+| ---- | ---------- | -- |
+| example.com | A | 35.185.44.232 |
+| _gitlab-pages-verification-code.example.com | TXT | gitlab-pages-verification-code=00112233445566778899aabbccddeeff |
+|---+---|
+| www.example.com | CNAME | namespace.gitlab.io |
+| _gitlab-pages-verification-code.www.example.com | TXT | gitlab-pages-verification-code=00112233445566778899aabbccddeeff |
+
+If you're using CloudFlare, check
+[Redirecting `www.domain.com` to `domain.com` with Cloudflare](#redirecting-wwwdomaincom-to-domaincom-with-cloudflare).
+
+> **Notes**:
+>
+> - **Do not** use a CNAME record if you want to point your
+ `domain.com` to your GitLab Pages site. Use an `A` record instead.
+> - **Do not** add any special chars after the default Pages
+ domain. E.g., don't point `subdomain.domain.com` to
+ or `namespace.gitlab.io/`. Some domain hosting providers may request a trailling dot (`namespace.gitlab.io.`), though.
+> - GitLab Pages IP on GitLab.com [was changed](https://about.gitlab.com/2017/03/06/we-are-changing-the-ip-of-gitlab-pages-on-gitlab-com/) in 2017.
+> - GitLab Pages IP on GitLab.com [has changed](https://about.gitlab.com/2018/07/19/gcp-move-update/#gitlab-pages-and-custom-domains)
+ from `52.167.214.135` to `35.185.44.232` in 2018.
+
+#### 4. Verify the domain's ownership
+
+Once you have added all the DNS records:
+
+1. Go back at your project's **Settings > Pages**.
+1. Locate your domain name and click **Details**.
+1. Click the **Retry verification** button to activate your new domain.
+
+![Verify your domain](img/retry_domain_verification_v12_0.png)
+
+As soon as your domain becomes active, your website will be available
+through your domain name.
+
+CAUTION: **Caution:**
+Considering GitLab instances with domain verification enabled,
+if the domain cannot be verified for 7 days, it will be removed
+from the GitLab project.
+
+> **Notes:**
+>
+> - Domain verification is **required for GitLab.com users**;
+ for GitLab self-managed instances, your GitLab administrator has the option
+ to [disabled custom domain verification](../../../../administration/pages/index.md#custom-domain-verification).
+> - [DNS propagation may take some time (up to 24h)](http://www.inmotionhosting.com/support/domain-names/dns-nameserver-changes/domain-names-dns-changes),
+ although it's usually a matter of minutes to complete. Until it does, verification
+ will fail and attempts to visit your domain will respond with a 404.
+> - Once your domain has been verified, leave the verification record
+ in place: your domain will be periodically reverified, and may be
+ disabled if the record is removed.
+
+### Adding more domain aliases
+
+You can add more than one alias (custom domains and subdomains) to the same project.
+An alias can be understood as having many doors leading to the same room.
+
+All the aliases you've set to your site will be listed on **Setting > Pages**.
+From that page, you can view, add, and remove them.
+
+### Redirecting `www.domain.com` to `domain.com` with Cloudflare
+
+If you use Cloudflare, you can redirect `www` to `domain.com` without adding both
+`www.domain.com` and `domain.com` to GitLab. This happens due to a [Cloudflare feature that creates
+a 301 redirect as a "page rule"](https://gitlab.com/gitlab-org/gitlab-ce/issues/48848#note_87314849) for redirecting `www.domain.com` to `domain.com`. In this case,
+you can use the following setup:
+
+1. In Cloudflare, create a DNS `A` record pointing `domain.com` to `35.185.44.232`.
+1. In GitLab, add the domain to GitLab Pages.
+1. In Cloudflare, create a DNS `TXT` record to verify your domain.
+1. In Cloudflare, create a DNS `CNAME` record pointing `www` to `domain.com`.
+
+## Adding an SSL/TLS certificate to Pages
+
+Read this document for an [overview on SSL/TLS certification](ssl_tls_concepts.md).
+
+### Requirements
+
+- A GitLab Pages website up and running accessible via a custom domain.
+- **A PEM certificate**: it is the certificate generated by the CA,
+ which needs to be added to the field **Certificate (PEM)**.
+- **An [intermediate certificate](https://en.wikipedia.org/wiki/Intermediate_certificate_authority)**: (aka "root certificate"), it is
+ the part of the encryption keychain that identifies the CA.
+ Usually it's combined with the PEM certificate, but there are
+ some cases in which you need to add them manually.
+ [CloudFlare certs](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/)
+ are one of these cases.
+- **A private key**, it's an encrypted key which validates
+ your PEM against your domain.
+
+### Steps
+
+- To add the certificate at the time you add a new domain, go to your
+ project's **Settings > Pages > New Domain**, add the domain name and the certificate.
+- To add the certificate to a domain previously added, go to your
+ project's **Settings > Pages**, locate your domain name, click **Details** and **Edit** to add the certificate.
+
+![Pages project - adding certificates](img/add_certificate_to_pages.png)
+
+1. Add the PEM certificate to its corresponding field.
+1. If your certificate is missing its intermediate, copy
+ and paste the root certificate (usually available from your CA website)
+ and paste it in the [same field as your PEM certificate](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/),
+ just jumping a line between them.
+1. Copy your private key and paste it in the last field.
+
+NOTE: **Note:**
+**Do not** open certificates or encryption keys in
+regular text editors. Always use code editors (such as
+Sublime Text, Atom, Dreamweaver, Brackets, etc).
+
+## Force HTTPS for GitLab Pages websites
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/28857) in GitLab 10.7.
+
+To make your website's visitors even more secure, you can choose to
+force HTTPS for GitLab Pages. By doing so, all attempts to visit your
+website via HTTP will be automatically redirected to HTTPS via 301.
+
+It works with both GitLab's default domain and with your custom
+domain (as long as you've set a valid certificate for it).
+
+To enable this setting:
+
+1. Navigate to your project's **Settings > Pages**.
+1. Tick the checkbox **Force HTTPS (requires valid certificates)**.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. --> \ No newline at end of file
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md
new file mode 100644
index 00000000000..2470e78819f
--- /dev/null
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md
@@ -0,0 +1,75 @@
+---
+type: concepts
+---
+
+# SSL/TLS Certificates
+
+_Read this document for a brief overview of SSL/TLS certificates in
+the scope of GitLab Pages, for beginners in web development._
+
+Every GitLab Pages project on GitLab.com will be available under
+HTTPS for the default Pages domain (`*.gitlab.io`). Once you set
+up your Pages project with your custom (sub)domain, if you want
+it secured by HTTPS, you will have to issue a certificate for that
+(sub)domain and install it on your project.
+
+NOTE: **Note:**
+Certificates are NOT required to add to your custom
+(sub)domain on your GitLab Pages project, though they are
+highly recommendable.
+
+Let's start with an introduction to the importance of HTTPS.
+
+## Why should I care about HTTPS?
+
+This might be your first question. If our sites are hosted by GitLab Pages,
+they are static, hence we are not dealing with server-side scripts
+nor credit card transactions, then why do we need secure connections?
+
+Back in the 1990s, where HTTPS came out, [SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security#SSL_1.0.2C_2.0_and_3.0) was considered a "special"
+security measure, necessary just for big companies, like banks and shoppings sites
+with financial transactions.
+Now we have a different picture. [According to Josh Aas](https://letsencrypt.org/2015/10/29/phishing-and-malware.html), Executive Director at [ISRG](https://en.wikipedia.org/wiki/Internet_Security_Research_Group):
+
+> _We’ve since come to realize that HTTPS is important for almost all websites. It’s important for any website that allows people to log in with a password, any website that [tracks its users](https://www.washingtonpost.com/news/the-switch/wp/2013/12/10/nsa-uses-google-cookies-to-pinpoint-targets-for-hacking/) in any way, any website that [doesn’t want its content altered](http://arstechnica.com/tech-policy/2014/09/why-comcasts-javascript-ad-injections-threaten-security-net-neutrality/), and for any site that offers content people might not want others to know they are consuming. We’ve also learned that any site not secured by HTTPS [can be used to attack other sites](https://krebsonsecurity.com/2015/04/dont-be-fodder-for-chinas-great-cannon/)._
+
+Therefore, the reason why certificates are so important is that they encrypt
+the connection between the **client** (you, me, your visitors)
+and the **server** (where you site lives), through a keychain of
+authentications and validations.
+
+How about taking Josh's advice and protecting our sites too? We will be
+well supported, and we'll contribute to a safer internet.
+
+## Organizations supporting HTTPS
+
+There is a huge movement in favor of securing all the web. W3C fully
+[supports the cause](https://w3ctag.github.io/web-https/) and explains very well
+the reasons for that. Richard Barnes, a writer for Mozilla Security Blog,
+suggested that [Firefox would deprecate HTTP](https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/),
+and would no longer accept unsecured connections. Recently, Mozilla published a
+[communication](https://blog.mozilla.org/security/2016/03/29/march-2016-ca-communication/)
+reiterating the importance of HTTPS.
+
+## Issuing Certificates
+
+GitLab Pages accepts certificates provided in the [PEM](https://support.quovadisglobal.com/kb/a37/what-is-pem-format.aspx) format, issued by
+[Certificate Authorities (CAs)](https://en.wikipedia.org/wiki/Certificate_authority) or as
+[self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate). Note that [self-signed certificates are typically not used](https://securingtomorrow.mcafee.com/other-blogs/mcafee-labs/self-signed-certificates-secure-so-why-ban/)
+for public websites for security reasons and to ensure that browsers trust your site's certificate.
+
+There are various kinds of certificates, each one
+with a certain security level. A static personal website will
+not require the same security level as an online banking web app,
+for instance.
+
+There are some certificate authorities that
+offer free certificates, aiming to make the internet more secure
+to everyone. The most popular is [Let's Encrypt](https://letsencrypt.org/),
+which issues certificates trusted by most of browsers, it's open
+source, and free to use. See our tutorial on [how to secure your GitLab Pages website with Let's Encrypt](../lets_encrypt_for_gitlab_pages.md).
+
+Similarly popular are [certificates issued by CloudFlare](https://www.cloudflare.com/ssl/),
+which also offers a [free CDN service](https://blog.cloudflare.com/cloudflares-free-cdn-and-you/).
+Their certs are valid up to 15 years. See the tutorial on
+[how to add a CloudFlare Certificate to your GitLab Pages website](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/).
diff --git a/doc/user/project/pages/getting_started_part_three.md b/doc/user/project/pages/getting_started_part_three.md
index bc9a11504cd..9bc9fe97fd3 100644
--- a/doc/user/project/pages/getting_started_part_three.md
+++ b/doc/user/project/pages/getting_started_part_three.md
@@ -1,314 +1 @@
----
-last_updated: 2019-06-25
-type: concepts, reference, howto
----
-
-# GitLab Pages custom domains and SSL/TLS Certificates
-
-Setting up GitLab Pages with custom domains, and adding SSL/TLS certificates to them, are optional features of GitLab Pages.
-
-These steps assume you've already [set your site up](getting_started_part_two.md) and it's served under the default Pages domain `namespace.gitlab.io`, or `namespace.gitlab.io/project-name`.
-
-## Adding your custom domain to GitLab Pages
-
-To use one or more custom domain with your Pages site, there are two things
-you should consider first, which we'll cover in this guide:
-
-1. Either if you're adding a **root domain** or a **subdomain**, for which
- you'll need to set up [DNS records](#dns-records)
-1. Whether you want to add an [SSL/TLS certificate](#ssltls-certificates) or not
-
-To finish the association, you need to [add your domain to your project's Pages settings](#add-your-custom-domain-to-gitlab-pages-settings).
-
-Let's start from the beginning with [DNS records](#dns-records).
-If you already know how they work and want to skip the introduction to DNS,
-you may be interested in skipping it until the [TL;DR](#tldr) section below.
-
-### DNS Records
-
-A Domain Name System (DNS) web service routes visitors to websites
-by translating domain names (such as `www.example.com`) into the
-numeric IP addresses (such as `192.0.2.1`) that computers use to
-connect to each other.
-
-A DNS record is created to point a (sub)domain to a certain location,
-which can be an IP address or another domain. In case you want to use
-GitLab Pages with your own (sub)domain, you need to access your domain's
-registrar control panel to add a DNS record pointing it back to your
-GitLab Pages site.
-
-Note that **how to** add DNS records depends on which server your domain
-is hosted on. Every control panel has its own place to do it. If you are
-not an admin of your domain, and don't have access to your registrar,
-you'll need to ask for the technical support of your hosting service
-to do it for you.
-
-To help you out, we've gathered some instructions on how to do that
-for the most popular hosting services:
-
-- [Amazon](http://docs.aws.amazon.com/gettingstarted/latest/swh/getting-started-configure-route53.html)
-- [Bluehost](https://my.bluehost.com/cgi/help/559)
-- [CloudFlare](https://support.cloudflare.com/hc/en-us/articles/200169096-How-do-I-add-A-records-)
-- [cPanel](https://documentation.cpanel.net/display/ALD/Edit+DNS+Zone)
-- [DreamHost](https://help.dreamhost.com/hc/en-us/articles/215414867-How-do-I-add-custom-DNS-records-)
-- [Go Daddy](https://www.godaddy.com/help/add-an-a-record-19238)
-- [Hostgator](http://support.hostgator.com/articles/changing-dns-records)
-- [Inmotion hosting](https://my.bluehost.com/cgi/help/559)
-- [Media Temple](https://mediatemple.net/community/products/dv/204403794/how-can-i-change-the-dns-records-for-my-domain)
-- [Microsoft](https://msdn.microsoft.com/en-us/library/bb727018.aspx)
-
-If your hosting service is not listed above, you can just try to
-search the web for `how to add dns record on <my hosting service>`.
-
-#### DNS A record
-
-In case you want to point a root domain (`example.com`) to your
-GitLab Pages site, deployed to `namespace.gitlab.io`, you need to
-log into your domain's admin control panel and add a DNS `A` record
-pointing your domain to Pages' server IP address. For projects on
-GitLab.com, this IP is `35.185.44.232`. For projects living in
-other GitLab instances (CE or EE), please contact your sysadmin
-asking for this information (which IP address is Pages server
-running on your instance).
-
-**Practical Example:**
-
-![DNS A record pointing to GitLab.com Pages server](img/dns_add_new_a_record_example_updated_2018.png)
-
-CAUTION: **Caution:**
-Note that if you use your root domain for your GitLab Pages website
-**only**, and if your domain registrar supports this feature, you can
-add a DNS apex `CNAME` record instead of an `A` record. The main
-advantage of doing so is that when GitLab Pages IP on GitLab.com
-changes for whatever reason, you don't need to update your `A` record.
-There may be a few exceptions, but **this method is not recommended**
-as it most likely won't work if you set an `MX` record for your root domain.
-
-#### DNS CNAME record
-
-In case you want to point a subdomain (`hello-world.example.com`)
-to your GitLab Pages site initially deployed to `namespace.gitlab.io`,
-you need to log into your domain's admin control panel and add a DNS
-`CNAME` record pointing your subdomain to your website URL
-(`namespace.gitlab.io`) address.
-
-Note that, whether it's a user or a project website, the `CNAME`
-should point to your Pages domain (`namespace.gitlab.io`),
-without any `/project-name`.
-
-**Practical Example:**
-
-![DNS CNAME record pointing to GitLab.com project](img/dns_cname_record_example.png)
-
-#### DNS TXT record
-
-Unless your GitLab administrator has [disabled custom domain verification](../../../administration/pages/index.md#custom-domain-verification),
-you'll have to prove that you own the domain by creating a `TXT` record
-containing a verification code. The code will be displayed after you
-[add your custom domain to GitLab Pages settings](#add-your-custom-domain-to-gitlab-pages-settings).
-
-If using a [DNS A record](#dns-a-record), you can place the TXT record directly
-under the domain. If using a [DNS CNAME record](#dns-cname-record), the two record types won't
-co-exist, so you need to place the TXT record in a special subdomain of its own.
-
-If the domain cannot be verified for 7 days, it will be removed from the GitLab project.
-
-#### TL;DR
-
-For root domains (`domain.com`), set a DNS `A` record and verify your
-domain's ownership with a TXT record:
-
-| From | DNS Record | To |
-| ---- | ---------- | -- |
-| domain.com | A | 35.185.44.232 |
-| domain.com | TXT | gitlab-pages-verification-code=00112233445566778899aabbccddeeff |
-
-For subdomains (`subdomain.domain.com`), set a DNS `CNAME` record and
-verify your domain's ownership with a TXT record:
-
-| From | DNS Record | To |
-| ---- | ---------- | -- |
-| subdomain.domain.com | CNAME | namespace.gitlab.io |
-| _gitlab-pages-verification-code.subdomain.domain.com | TXT | gitlab-pages-verification-code=00112233445566778899aabbccddeeff |
-
-> **Notes**:
->
-> - **Do not** use a CNAME record if you want to point your
- `domain.com` to your GitLab Pages site. Use an `A` record instead.
-> - **Do not** add any special chars after the default Pages
- domain. E.g., **do not** point your `subdomain.domain.com` to
- `namespace.gitlab.io.` or `namespace.gitlab.io/`.
-> - GitLab Pages IP on GitLab.com [was changed](https://about.gitlab.com/2017/03/06/we-are-changing-the-ip-of-gitlab-pages-on-gitlab-com/) in 2017.
-> - GitLab Pages IP on GitLab.com [has been changed](https://about.gitlab.com/2018/07/19/gcp-move-update/#gitlab-pages-and-custom-domains)
- from `52.167.214.135` to `35.185.44.232` in 2018.
-
-### Add your custom domain to GitLab Pages settings
-
-Once you've set the DNS record, you'll need navigate to your project's
-**Setting > Pages** and click **+ New domain** to add your custom domain to
-GitLab Pages. You can choose whether to add an [SSL/TLS certificate](#ssltls-certificates)
-to make your website accessible under HTTPS or leave it blank. If you don't add a certificate,
-your site will be accessible only via HTTP:
-
-![Add new domain](img/add_certificate_to_pages.png)
-
-Once you have added a new domain, you will need to **verify your ownership**
-(unless the GitLab administrator has disabled this feature). A verification code
-will be shown to you; add it as a [DNS TXT record](#dns-txt-record), then press
-the "Verify ownership" button to activate your new domain:
-
-![Verify your domain](img/verify_your_domain.png)
-
-Once your domain has been verified, leave the verification record in place -
-your domain will be periodically reverified, and may be disabled if the record
-is removed.
-
-You can add more than one alias (custom domains and subdomains) to the same project.
-An alias can be understood as having many doors leading to the same room.
-
-All the aliases you've set to your site will be listed on **Setting > Pages**.
-From that page, you can view, add, and remove them.
-
-Note that [DNS propagation may take some time (up to 24h)](http://www.inmotionhosting.com/support/domain-names/dns-nameserver-changes/domain-names-dns-changes),
-although it's usually a matter of minutes to complete. Until it does, verification
-will fail and attempts to visit your domain will respond with a 404.
-
-### Redirecting `www.domain.com` to `domain.com` with Cloudflare
-
-If you use Cloudflare, you can redirect `www` to `domain.com` without the need of adding both
-`www.domain.com` and `domain.com` to GitLab. This happens due to a [Cloudflare feature that creates
-a 301 redirect as a "page rule"](https://gitlab.com/gitlab-org/gitlab-ce/issues/48848#note_87314849) for redirecting `www.domain.com` to `domain.com`. In this case,
-you can use the following setup:
-
-- In Cloudflare, create a DNS `A` record pointing `domain.com` to `35.185.44.232`
-- In GitLab, add the domain to GitLab Pages
-- In Cloudflare, create a DNS `TXT` record to verify your domain
-- In Cloudflare, create a DNS `CNAME` record pointing `www` to `domain.com`
-
-## SSL/TLS Certificates
-
-Every GitLab Pages project on GitLab.com will be available under
-HTTPS for the default Pages domain (`*.gitlab.io`). Once you set
-up your Pages project with your custom (sub)domain, if you want
-it secured by HTTPS, you will have to issue a certificate for that
-(sub)domain and install it on your project.
-
->**Note:**
-Certificates are NOT required to add to your custom
-(sub)domain on your GitLab Pages project, though they are
-highly recommendable.
-
-Let's start with an introduction to the importance of HTTPS.
-Alternatively, jump ahead to [adding certificates to your project](#adding-certificates-to-pages).
-
-### Why should I care about HTTPS?
-
-This might be your first question. If our sites are hosted by GitLab Pages,
-they are static, hence we are not dealing with server-side scripts
-nor credit card transactions, then why do we need secure connections?
-
-Back in the 1990s, where HTTPS came out, [SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security#SSL_1.0.2C_2.0_and_3.0) was considered a "special"
-security measure, necessary just for big companies, like banks and shoppings sites
-with financial transactions.
-Now we have a different picture. [According to Josh Aas](https://letsencrypt.org/2015/10/29/phishing-and-malware.html), Executive Director at [ISRG](https://en.wikipedia.org/wiki/Internet_Security_Research_Group):
-
-> _We’ve since come to realize that HTTPS is important for almost all websites. It’s important for any website that allows people to log in with a password, any website that [tracks its users](https://www.washingtonpost.com/news/the-switch/wp/2013/12/10/nsa-uses-google-cookies-to-pinpoint-targets-for-hacking/) in any way, any website that [doesn’t want its content altered](http://arstechnica.com/tech-policy/2014/09/why-comcasts-javascript-ad-injections-threaten-security-net-neutrality/), and for any site that offers content people might not want others to know they are consuming. We’ve also learned that any site not secured by HTTPS [can be used to attack other sites](https://krebsonsecurity.com/2015/04/dont-be-fodder-for-chinas-great-cannon/)._
-
-Therefore, the reason why certificates are so important is that they encrypt
-the connection between the **client** (you, me, your visitors)
-and the **server** (where you site lives), through a keychain of
-authentications and validations.
-
-How about taking Josh's advice and protecting our sites too? We will be
-well supported, and we'll contribute to a safer internet.
-
-### Organizations supporting HTTPS
-
-There is a huge movement in favor of securing all the web. W3C fully
-[supports the cause](https://w3ctag.github.io/web-https/) and explains very well
-the reasons for that. Richard Barnes, a writer for Mozilla Security Blog,
-suggested that [Firefox would deprecate HTTP](https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/),
-and would no longer accept unsecured connections. Recently, Mozilla published a
-[communication](https://blog.mozilla.org/security/2016/03/29/march-2016-ca-communication/)
-reiterating the importance of HTTPS.
-
-## Issuing Certificates
-
-GitLab Pages accepts certificates provided in the [PEM](https://support.quovadisglobal.com/kb/a37/what-is-pem-format.aspx) format, issued by
-[Certificate Authorities (CAs)](https://en.wikipedia.org/wiki/Certificate_authority) or as
-[self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate). Note that [self-signed certificates are typically not used](https://securingtomorrow.mcafee.com/other-blogs/mcafee-labs/self-signed-certificates-secure-so-why-ban/)
-for public websites for security reasons and to ensure that browsers trust your site's certificate.
-
-There are various kinds of certificates, each one
-with a certain security level. A static personal website will
-not require the same security level as an online banking web app,
-for instance.
-
-There are some certificate authorities that
-offer free certificates, aiming to make the internet more secure
-to everyone. The most popular is [Let's Encrypt](https://letsencrypt.org/),
-which issues certificates trusted by most of browsers, it's open
-source, and free to use. See our tutorial on [how to secure your GitLab Pages website with Let's Encrypt](lets_encrypt_for_gitlab_pages.md).
-
-Similarly popular are [certificates issued by CloudFlare](https://www.cloudflare.com/ssl/),
-which also offers a [free CDN service](https://blog.cloudflare.com/cloudflares-free-cdn-and-you/).
-Their certs are valid up to 15 years. See the tutorial on
-[how to add a CloudFlare Certificate to your GitLab Pages website](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/).
-
-### Adding certificates to Pages
-
-Regardless the CA you choose, the steps to add your certificate to
-your Pages project are the same.
-
-#### Requirements
-
-1. A PEM certificate
-1. An intermediate certificate
-1. A private key
-
-![Pages project - adding certificates](img/add_certificate_to_pages.png)
-
-These fields are found under your **Project**'s **Settings** > **Pages** > **New Domain**.
-
-#### Certificate types
-
-- A PEM certificate is the certificate generated by the CA,
- which needs to be added to the field **Certificate (PEM)**.
-- An [intermediate certificate](https://en.wikipedia.org/wiki/Intermediate_certificate_authority) (aka "root certificate") is
- the part of the encryption keychain that identifies the CA.
- Usually it's combined with the PEM certificate, but there are
- some cases in which you need to add them manually.
- [CloudFlare certs](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/)
- are one of these cases.
-- A private key is an encrypted key which validates
- your PEM against your domain.
-
-#### Add the certificate to your project
-
-Once you've met the requirements:
-
-- Your PEM certificate needs to be added to the first field.
-- If your certificate is missing its intermediate, copy
- and paste the root certificate (usually available from your CA website)
- and paste it in the [same field as your PEM certificate](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/),
- just jumping a line between them.
-- Copy your private key and paste it in the last field.
-
-NOTE: **Note:**
-**Do not** open certificates or encryption keys in
-regular text editors. Always use code editors (such as
-Sublime Text, Atom, Dreamweaver, Brackets, etc).
-
-## Force HTTPS for GitLab Pages websites
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/28857) in GitLab 10.7.
-
-To make your website's visitors even more secure, you can choose to
-force HTTPS for GitLab Pages. By doing so, all attempts to visit your
-website via HTTP will be automatically redirected to HTTPS via 301.
-
-It works with both GitLab's default domain and with your custom
-domain (as long as you've set a valid certificate for it).
-
-To enable this setting, navigate to your project's **Settings > Pages**
-and tick the checkbox **Force HTTPS (requires valid certificates)**.
+This document was moved to [another location](custom_domains_ssl_tls_certification/index.md).
diff --git a/doc/user/project/pages/getting_started_part_two.md b/doc/user/project/pages/getting_started_part_two.md
index fe92d19567d..743c360f075 100644
--- a/doc/user/project/pages/getting_started_part_two.md
+++ b/doc/user/project/pages/getting_started_part_two.md
@@ -22,7 +22,7 @@ Optional Features:
1. **Optional**: an SSL/TLS certificate so your custom
domain is accessible under HTTPS.
-The optional settings, custom domain, DNS records, and SSL/TLS certificates, are described in [Part 3](getting_started_part_three.md)).
+The optional settings, custom domain, DNS records, and SSL/TLS certificates, are described in [GitLab Pages custom domains and SSL/TLS Certificates](custom_domains_ssl_tls_certification/index.md)).
## Project
@@ -169,4 +169,4 @@ baseurl: ""
## Custom Domains
GitLab Pages supports custom domains and subdomains, served under HTTP or HTTPS.
-See [GitLab Pages custom domains and SSL/TLS Certificates](getting_started_part_three.md) for more information.
+See [GitLab Pages custom domains and SSL/TLS Certificates](custom_domains_ssl_tls_certification/index.md) for more information.
diff --git a/doc/user/project/pages/img/pages_project_templates_11-8.png b/doc/user/project/pages/img/pages_project_templates_v11_8.png
index a645d28260b..a645d28260b 100644
--- a/doc/user/project/pages/img/pages_project_templates_11-8.png
+++ b/doc/user/project/pages/img/pages_project_templates_v11_8.png
Binary files differ
diff --git a/doc/user/project/pages/img/verify_your_domain.png b/doc/user/project/pages/img/verify_your_domain.png
deleted file mode 100644
index d870f9e6505..00000000000
--- a/doc/user/project/pages/img/verify_your_domain.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 64b1e259292..e9d2e9a0059 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -101,7 +101,7 @@ To get started with GitLab Pages, you can either:
1. Select **Create from Template**.
1. Choose one of the templates starting with **Pages**:
- ![Project templates for Pages](img/pages_project_templates_11-8.png)
+ ![Project templates for Pages](img/pages_project_templates_v11_8.png)
1. From the left sidebar, navigate to your project's **CI/CD > Pipelines**
and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
@@ -115,8 +115,8 @@ will run a new pipeline to publish your changes to the server.
_Advanced options:_
-- [Use a custom domain](getting_started_part_three.md#adding-your-custom-domain-to-gitlab-pages)
-- Apply [SSL/TLS certification](getting_started_part_three.md#ssltls-certificates) to your custom domain
+- [Use a custom domain](custom_domains_ssl_tls_certification/index.md#set-up-pages-with-a-custom-domain)
+- Apply [SSL/TLS certification](custom_domains_ssl_tls_certification/index.md#adding-an-ssltls-certificate-to-pages) to your custom domain
## Availability
@@ -142,7 +142,7 @@ To learn more about configuration options for GitLab Pages, read the following:
| [GitLab CI/CD for GitLab Pages](getting_started_part_four.md) | Understand how to create your own `.gitlab-ci.yml` for your site. |
| [Exploring GitLab Pages](introduction.md) | Requirements, technical aspects, specific GitLab CI's configuration options, Access Control, custom 404 pages, limitations, FAQ. |
|---+---|
-| [Custom domains and SSL/TLS Certificates](getting_started_part_three.md) | How to add custom domains and subdomains to your website, configure DNS records and SSL/TLS certificates. |
+| [Custom domains and SSL/TLS Certificates](custom_domains_ssl_tls_certification/index.md) | How to add custom domains and subdomains to your website, configure DNS records and SSL/TLS certificates. |
| [CloudFlare certificates](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) | Secure your Pages site with CloudFlare certificates. |
| [Let's Encrypt certificates](lets_encrypt_for_gitlab_pages.md) | Secure your Pages site with Let's Encrypt certificates. |
|---+---|
diff --git a/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
index 91a660c0f7a..cc129f90b7a 100644
--- a/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
+++ b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
@@ -18,9 +18,9 @@ To follow along with this tutorial, we assume you already have:
- Created a [project](getting_started_part_two.md) in GitLab which
contains your website's source code.
-- Acquired a domain (`example.com`) and added a [DNS entry](getting_started_part_three.md#dns-records)
+- Acquired a domain (`example.com`) and added a [DNS entry](custom_domains_ssl_tls_certification/index.md#set-up-pages-with-a-custom-domain)
pointing it to your Pages website.
-- [Added your domain to your Pages project](getting_started_part_three.md#add-your-custom-domain-to-gitlab-pages-settings)
+- [Added your domain to your Pages project](custom_domains_ssl_tls_certification/index.md#steps)
and verified your ownership.
- Cloned your project into your computer.
- Your website up and running, served under HTTP protocol at `http://example.com`.
@@ -36,111 +36,111 @@ operating systems the steps might be slightly different. Follow the
[CertBot instructions](https://certbot.eff.org/) according to your OS.
1. On your computer, open a terminal and navigate to your repository's
- root directory:
+ root directory:
- ```bash
- cd path/to/dir
- ```
+ ```bash
+ cd path/to/dir
+ ```
1. Install CertBot (the tool Let's Encrypt uses to issue certificates):
- ```bash
- brew install certbot
- ```
+ ```bash
+ brew install certbot
+ ```
1. Request a certificate for your domain (`example.com`) and
- provide an email account (`your@email.com`) to receive notifications:
+ provide an email account (`your@email.com`) to receive notifications:
- ```bash
- sudo certbot certonly -a manual -d example.com --email your@email.com
- ```
+ ```bash
+ sudo certbot certonly -a manual -d example.com --email your@email.com
+ ```
- Alternatively, you can register without adding an e-mail account,
- but you won't be notified about the certificate expiration's date:
+ Alternatively, you can register without adding an e-mail account,
+ but you won't be notified about the certificate expiration's date:
- ```bash
- sudo certbot certonly -a manual -d example.com --register-unsafely-without-email
- ```
+ ```bash
+ sudo certbot certonly -a manual -d example.com --register-unsafely-without-email
+ ```
- TIP: **Tip:**
- Read through CertBot's documentation on their
- [command line options](https://certbot.eff.org/docs/using.html#certbot-command-line-options).
+ TIP: **Tip:**
+ Read through CertBot's documentation on their
+ [command line options](https://certbot.eff.org/docs/using.html#certbot-command-line-options).
1. You'll be prompted with a message to agree with their terms.
- Press `A` to agree and `Y` to let they log your IP.
+ Press `A` to agree and `Y` to let they log your IP.
- CertBot will then prompt you with the following message:
+ CertBot will then prompt you with the following message:
- ```bash
- Create a file containing just this data:
+ ```bash
+ Create a file containing just this data:
- Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP.HUGNKk82jlsmOOfphlt8Jy69iuglsn095nxOMH9j3Yb
+ Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP.HUGNKk82jlsmOOfphlt8Jy69iuglsn095nxOMH9j3Yb
- And make it available on your web server at this URL:
+ And make it available on your web server at this URL:
- http://example.com/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP
+ http://example.com/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP
- Press Enter to Continue
- ```
+ Press Enter to Continue
+ ```
1. **Do not press Enter yet.** Let's Encrypt will need to verify your
- domain ownership before issuing the certificate. To do so, create 3
- consecutive directories under your website's root:
- `/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP/`
- and add to the last folder an `index.html` file containing the content
- referred on the previous prompt message:
-
- ```bash
- Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP.HUGNKk82jlsmOOfphlt8Jy69iuglsn095nxOMH9j3Yb
- ```
-
- Note that this file needs to be accessed under
- `http://example.com/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP`
- to allow Let's Encrypt to verify the ownership of your domain,
- therefore, it needs to be part of the website content under the
- repo's [`public`](index.md#how-it-works) folder.
+ domain ownership before issuing the certificate. To do so, create 3
+ consecutive directories under your website's root:
+ `/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP/`
+ and add to the last folder an `index.html` file containing the content
+ referred on the previous prompt message:
+
+ ```bash
+ Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP.HUGNKk82jlsmOOfphlt8Jy69iuglsn095nxOMH9j3Yb
+ ```
+
+ Note that this file needs to be accessed under
+ `http://example.com/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP`
+ to allow Let's Encrypt to verify the ownership of your domain,
+ therefore, it needs to be part of the website content under the
+ repo's [`public`](index.md#how-it-works) folder.
1. Add, commit, and push the file into your repo in GitLab. Once the pipeline
- passes, press **Enter** on your terminal to continue issuing your
- certificate. CertBot will then prompt you with the following message:
-
- ```bash
- Waiting for verification...
- Cleaning up challenges
-
- IMPORTANT NOTES:
- - Congratulations! Your certificate and chain have been saved at:
- /etc/letsencrypt/live/example.com/fullchain.pem
- Your key file has been saved at:
- /etc/letsencrypt/live/example.com/privkey.pem
- Your cert will expire on 2019-03-12. To obtain a new or tweaked
- version of this certificate in the future, simply run certbot
- again. To non-interactively renew *all* of your certificates, run
- "certbot renew"
- - If you like Certbot, please consider supporting our work by:
-
- Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
- Donating to EFF: https://eff.org/donate-le
- ```
+ passes, press **Enter** on your terminal to continue issuing your
+ certificate. CertBot will then prompt you with the following message:
+
+ ```bash
+ Waiting for verification...
+ Cleaning up challenges
+
+ IMPORTANT NOTES:
+ - Congratulations! Your certificate and chain have been saved at:
+ /etc/letsencrypt/live/example.com/fullchain.pem
+ Your key file has been saved at:
+ /etc/letsencrypt/live/example.com/privkey.pem
+ Your cert will expire on 2019-03-12. To obtain a new or tweaked
+ version of this certificate in the future, simply run certbot
+ again. To non-interactively renew *all* of your certificates, run
+ "certbot renew"
+ - If you like Certbot, please consider supporting our work by:
+
+ Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
+ Donating to EFF: https://eff.org/donate-le
+ ```
## Add your certificate to GitLab Pages
Now that your certificate has been issued, let's add it to your Pages site:
1. Back at GitLab, navigate to your project's **Settings > Pages**,
- find your domain and click **Details** and **Edit** to add your certificate.
+ find your domain and click **Details** and **Edit** to add your certificate.
1. From your terminal, copy and paste the certificate into the first field
- **Certificate (PEM)**:
+ **Certificate (PEM)**:
- ```bash
- sudo cat /etc/letsencrypt/live/example.com/fullchain.pem | pbcopy
- ```
+ ```bash
+ sudo cat /etc/letsencrypt/live/example.com/fullchain.pem | pbcopy
+ ```
1. Copy and paste the private key into the second field **Key (PEM)**:
- ```bash
- sudo cat /etc/letsencrypt/live/example.com/privkey.pem | pbcopy
- ```
+ ```bash
+ sudo cat /etc/letsencrypt/live/example.com/privkey.pem | pbcopy
+ ```
1. Click **Save changes** to apply them to your website.
1. Wait a few minutes for the configuration changes to take effect.
diff --git a/doc/user/project/pipelines/job_artifacts.md b/doc/user/project/pipelines/job_artifacts.md
index 1966b136e9d..2411744c874 100644
--- a/doc/user/project/pipelines/job_artifacts.md
+++ b/doc/user/project/pipelines/job_artifacts.md
@@ -67,8 +67,6 @@ artifacts in case you changed your mind and want to keep them.
![Job artifacts browser button](img/job_artifacts_browser_button.png)
----
-
The archive browser shows the name and the actual file size of each file in the
archive. If your artifacts contained directories, then you are also able to
browse inside them.
@@ -80,8 +78,6 @@ one HTML file that you can view directly online when
![Job artifacts browser](img/job_artifacts_browser.png)
----
-
## Downloading artifacts
If you need to download the whole archive, there are buttons in various places
@@ -90,22 +86,22 @@ inside GitLab that make that possible.
1. While on the pipelines page, you can see the download icon for each job's
artifacts archive in the right corner:
- ![Job artifacts in Pipelines page](img/job_artifacts_pipelines_page.png)
+ ![Job artifacts in Pipelines page](img/job_artifacts_pipelines_page.png)
1. While on the **Jobs** page, you can see the download icon for each job's
artifacts archive in the right corner:
- ![Job artifacts in Builds page](img/job_artifacts_builds_page.png)
+ ![Job artifacts in Builds page](img/job_artifacts_builds_page.png)
1. While inside a specific job, you are presented with a download button
along with the one that browses the archive:
- ![Job artifacts browser button](img/job_artifacts_browser_button.png)
+ ![Job artifacts browser button](img/job_artifacts_browser_button.png)
1. And finally, when browsing an archive you can see the download button at
the top right corner:
- ![Job artifacts browser](img/job_artifacts_browser.png)
+ ![Job artifacts browser](img/job_artifacts_browser.png)
## Downloading the latest artifacts
diff --git a/doc/user/project/pipelines/settings.md b/doc/user/project/pipelines/settings.md
index 24e15a37a40..e60da6a3e59 100644
--- a/doc/user/project/pipelines/settings.md
+++ b/doc/user/project/pipelines/settings.md
@@ -25,10 +25,10 @@ in `.gitlab-ci.yml`.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/28919) in GitLab 12.0.
NOTE: **Note**:
-As of GitLab 12.0, newly created projects will automatically have a default
+As of GitLab 12.0, newly created projects will automatically have a default
`git depth` value of `50`.
-It is possible to limit the number of changes that GitLab CI/CD will fetch when cloning
+It is possible to limit the number of changes that GitLab CI/CD will fetch when cloning
a repository. Setting a limit to `git depth` can speed up Pipelines execution. Maximum
allowed value is `1000`.
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 8b8aa51b6dd..948ac91a886 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -34,19 +34,19 @@ discussions, and descriptions:
| `/remove_milestone` | Remove milestone | ✓ | ✓ |
| `/label ~label1 ~label2` | Add label(s). Label names can also start without ~ but mixed syntax is not supported. | ✓ | ✓ |
| `/unlabel ~label1 ~label2` | Remove all or specific label(s)| ✓ | ✓ |
-| `/relabel ~label1 ~label2` | Replace label | ✓ | ✓ |
-| <code>/copy_metadata &lt;#issue &#124; !merge_request&gt;</code> | Copy labels and milestone from other issue or merge request in the project | ✓ | ✓ |
-| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate | ✓ | ✓ |
+| `/relabel ~label1 ~label2` | Replace existing label(s) with those specified | ✓ | ✓ |
+| `/copy_metadata <#issue | !merge_request>` | Copy labels and milestone from other issue or merge request in the project | ✓ | ✓ |
+| `/estimate <1w 3d 2h 14m>` | Set time estimate | ✓ | ✓ |
| `/remove_estimate` | Remove time estimate | ✓ | ✓ |
-| <code>/spend &lt;time(1h 30m &#124; -1h 5m)&gt; &lt;date(YYYY-MM-DD)&gt;</code> | Add or subtract spent time; optionally, specify the date that time was spent on | ✓ | ✓ |
+| `/spend <time(1h 30m | -1h 5m)> <date(YYYY-MM-DD)>` | Add or subtract spent time; optionally, specify the date that time was spent on | ✓ | ✓ |
| `/remove_time_spent` | Remove time spent | ✓ | ✓ |
-| `/lock` | Lock the discussion | ✓ | ✓ |
-| `/unlock` | Unlock the discussion | ✓ | ✓ |
-| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code>| Set due date | ✓ | |
+| `/lock` | Lock the thread | ✓ | ✓ |
+| `/unlock` | Unlock the thread | ✓ | ✓ |
+| `/due <in 2 days | this Friday | December 31st>`| Set due date | ✓ | |
| `/remove_due_date` | Remove due date | ✓ | |
-| <code>/weight &lt;0 &#124; 1 &#124; 2 &#124; ...&gt;</code> | Set weight **(STARTER)** | ✓ | |
+| `/weight <0 | 1 | 2 | ...>` | Set weight **(STARTER)** | ✓ | |
| `/clear_weight` | Clears weight **(STARTER)** | ✓ | |
-| <code>/epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Add to epic **(ULTIMATE)** | ✓ | |
+| `/epic <&epic | group&epic | Epic URL>` | Add to epic **(ULTIMATE)** | ✓ | |
| `/remove_epic` | Removes from epic **(ULTIMATE)** | ✓ | |
| `/promote` | Promote issue to epic **(ULTIMATE)** | ✓ | |
| `/confidential` | Make confidential | ✓ | |
@@ -85,8 +85,8 @@ The following quick actions are applicable for epics threads and description:
| `/award :emoji:` | Toggle emoji award |
| `/label ~label1 ~label2` | Add label(s) |
| `/unlabel ~label1 ~label2` | Remove all or specific label(s) |
-| `/relabel ~label1 ~label2` | Replace label |
-| <code>/child_epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Adds child epic to epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ee/issues/7330)) |
-| <code>/remove_child_epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Removes child epic from epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ee/issues/7330)) |
-| <code>/parent_epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Sets parent epic to epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) |
-| <code>/remove_parent_epic | Removes parent epic from epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) |
+| `/relabel ~label1 ~label2` | Replace existing label(s) with those specified |
+| `/child_epic <&epic | group&epic | Epic URL>` | Adds child epic to epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ee/issues/7330)) |
+| `/remove_child_epic <&epic | group&epic | Epic URL>` | Removes child epic from epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ee/issues/7330)) |
+| `/parent_epic <&epic | group&epic | Epic URL>` | Sets parent epic to epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) |
+| `/remove_parent_epic` | Removes parent epic from epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) |
diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md
index cf0a986887e..3b0a045ef9c 100644
--- a/doc/user/project/repository/gpg_signed_commits/index.md
+++ b/doc/user/project/repository/gpg_signed_commits/index.md
@@ -45,94 +45,95 @@ started:
1. Generate the private/public key pair with the following command, which will
spawn a series of questions:
- ```sh
- gpg --full-gen-key
- ```
+ ```sh
+ gpg --full-gen-key
+ ```
- NOTE: **Note:**
- In some cases like Gpg4win on Windows and other macOS versions, the command
- here may be `gpg --gen-key`.
+ NOTE: **Note:**
+ In some cases like Gpg4win on Windows and other macOS versions, the command
+ here may be `gpg --gen-key`.
1. The first question is which algorithm can be used. Select the kind you want
or press <kbd>Enter</kbd> to choose the default (RSA and RSA):
- ```
- Please select what kind of key you want:
- (1) RSA and RSA (default)
- (2) DSA and Elgamal
- (3) DSA (sign only)
- (4) RSA (sign only)
- Your selection? 1
- ```
+ ```
+ Please select what kind of key you want:
+ (1) RSA and RSA (default)
+ (2) DSA and Elgamal
+ (3) DSA (sign only)
+ (4) RSA (sign only)
+ Your selection? 1
+ ```
1. The next question is key length. We recommend to choose the highest value
which is `4096`:
- ```
- RSA keys may be between 1024 and 4096 bits long.
- What keysize do you want? (2048) 4096
- Requested keysize is 4096 bits
- ```
+ ```
+ RSA keys may be between 1024 and 4096 bits long.
+ What keysize do you want? (2048) 4096
+ Requested keysize is 4096 bits
+ ```
+
1. Next, you need to specify the validity period of your key. This is something
subjective, and you can use the default value which is to never expire:
- ```
- Please specify how long the key should be valid.
- 0 = key does not expire
- <n> = key expires in n days
- <n>w = key expires in n weeks
- <n>m = key expires in n months
- <n>y = key expires in n years
- Key is valid for? (0) 0
- Key does not expire at all
- ```
+ ```
+ Please specify how long the key should be valid.
+ 0 = key does not expire
+ <n> = key expires in n days
+ <n>w = key expires in n weeks
+ <n>m = key expires in n months
+ <n>y = key expires in n years
+ Key is valid for? (0) 0
+ Key does not expire at all
+ ```
1. Confirm that the answers you gave were correct by typing `y`:
- ```
- Is this correct? (y/N) y
- ```
+ ```
+ Is this correct? (y/N) y
+ ```
1. Enter you real name, the email address to be associated with this key (should
match a verified email address you use in GitLab) and an optional comment
(press <kbd>Enter</kbd> to skip):
- ```
- GnuPG needs to construct a user ID to identify your key.
+ ```
+ GnuPG needs to construct a user ID to identify your key.
- Real name: Mr. Robot
- Email address: <your_email>
- Comment:
- You selected this USER-ID:
- "Mr. Robot <your_email>"
+ Real name: Mr. Robot
+ Email address: <your_email>
+ Comment:
+ You selected this USER-ID:
+ "Mr. Robot <your_email>"
- Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
- ```
+ Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
+ ```
1. Pick a strong password when asked and type it twice to confirm.
1. Use the following command to list the private GPG key you just created:
- ```
- gpg --list-secret-keys --keyid-format LONG <your_email>
- ```
+ ```
+ gpg --list-secret-keys --keyid-format LONG <your_email>
+ ```
- Replace `<your_email>` with the email address you entered above.
+ Replace `<your_email>` with the email address you entered above.
1. Copy the GPG key ID that starts with `sec`. In the following example, that's
`30F2B65B9246B6CA`:
- ```
- sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
- D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
- uid [ultimate] Mr. Robot <your_email>
- ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
- ```
+ ```
+ sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
+ D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
+ uid [ultimate] Mr. Robot <your_email>
+ ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
+ ```
1. Export the public key of that ID (replace your key ID from the previous step):
- ```
- gpg --armor --export 30F2B65B9246B6CA
- ```
+ ```
+ gpg --armor --export 30F2B65B9246B6CA
+ ```
1. Finally, copy the public key and [add it in your profile settings](#adding-a-gpg-key-to-your-account)
@@ -146,17 +147,17 @@ You can add a GPG key in your profile's settings:
1. On the upper right corner, click on your avatar and go to your **Settings**.
- ![Settings dropdown](../../../profile/img/profile_settings_dropdown.png)
+ ![Settings dropdown](../../../profile/img/profile_settings_dropdown.png)
1. Navigate to the **GPG keys** tab and paste your _public_ key in the 'Key'
box.
- ![Paste GPG public key](img/profile_settings_gpg_keys_paste_pub.png)
+ ![Paste GPG public key](img/profile_settings_gpg_keys_paste_pub.png)
1. Finally, click on **Add key** to add it to GitLab. You will be able to see
its fingerprint, the corresponding email address and creation date.
- ![GPG key single page](img/profile_settings_gpg_keys_single_key.png)
+ ![GPG key single page](img/profile_settings_gpg_keys_single_key.png)
## Associating your GPG key with Git
@@ -166,29 +167,29 @@ key to use.
1. Use the following command to list the private GPG key you just created:
- ```sh
- gpg --list-secret-keys --keyid-format LONG <your_email>
- ```
+ ```sh
+ gpg --list-secret-keys --keyid-format LONG <your_email>
+ ```
- Replace `<your_email>` with the email address you entered above.
+ Replace `<your_email>` with the email address you entered above.
1. Copy the GPG key ID that starts with `sec`. In the following example, that's
`30F2B65B9246B6CA`:
- ```
- sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
- D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
- uid [ultimate] Mr. Robot <your_email>
- ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
- ```
+ ```
+ sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
+ D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
+ uid [ultimate] Mr. Robot <your_email>
+ ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
+ ```
1. Tell Git to use that key to sign the commits:
- ```sh
- git config --global user.signingkey 30F2B65B9246B6CA
- ```
+ ```sh
+ git config --global user.signingkey 30F2B65B9246B6CA
+ ```
- Replace `30F2B65B9246B6CA` with your GPG key ID.
+ Replace `30F2B65B9246B6CA` with your GPG key ID.
1. (Optional) If Git is using `gpg` and you get errors like `secret key not available`
or `gpg: signing failed: secret key not available`, run the following command to
@@ -206,9 +207,9 @@ commits:
1. Commit like you used to, the only difference is the addition of the `-S` flag:
- ```
- git commit -S -m "My commit msg"
- ```
+ ```
+ git commit -S -m "My commit msg"
+ ```
1. Enter the passphrase of your GPG key when asked.
1. Push to GitLab and check that your commits [are verified](#verifying-commits).
@@ -227,13 +228,13 @@ git config --global commit.gpgsign true
"Verified" or "Unverified", depending on the verification status of the GPG
signature.
- ![Signed and unsigned commits](img/project_signed_and_unsigned_commits.png)
+ ![Signed and unsigned commits](img/project_signed_and_unsigned_commits.png)
1. By clicking on the GPG badge, details of the signature are displayed.
- ![Signed commit with verified signature](img/project_signed_commit_verified_signature.png)
+ ![Signed commit with verified signature](img/project_signed_commit_verified_signature.png)
- ![Signed commit with verified signature](img/project_signed_commit_unverified_signature.png)
+ ![Signed commit with verified signature](img/project_signed_commit_unverified_signature.png)
## Revoking a GPG key
diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md
index 7765a3d7438..7c711bc0b3b 100644
--- a/doc/user/project/repository/reducing_the_repo_size_using_git.md
+++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md
@@ -54,50 +54,50 @@ removed from the repository.
1. Navigate to your repository:
- ```
- cd my_repository/
- ```
+ ```
+ cd my_repository/
+ ```
1. Change to the branch you want to remove the big file from:
- ```
- git checkout master
- ```
+ ```
+ git checkout master
+ ```
1. Create a commit removing the large file from the branch, if it still exists:
- ```
- git rm path/to/big_file.mpg
- git commit -m 'Remove unneeded large file'
- ```
+ ```
+ git rm path/to/big_file.mpg
+ git commit -m 'Remove unneeded large file'
+ ```
1. Rewrite history:
- ```
- bfg --delete-files path/to/big_file.mpg
- ```
+ ```
+ bfg --delete-files path/to/big_file.mpg
+ ```
- An object map file will be written to `object-id-map.old-new.txt`. Keep it
- around - you'll need it for the final step!
+ An object map file will be written to `object-id-map.old-new.txt`. Keep it
+ around - you'll need it for the final step!
1. Force-push the changes to GitLab:
- ```
- git push --force-with-lease origin master
- ```
+ ```
+ git push --force-with-lease origin master
+ ```
- If this step fails, someone has changed the `master` branch while you were
- rewriting history. You could restore the branch and re-run BFG to preserve
- their changes, or use `git push --force` to overwrite their changes.
+ If this step fails, someone has changed the `master` branch while you were
+ rewriting history. You could restore the branch and re-run BFG to preserve
+ their changes, or use `git push --force` to overwrite their changes.
1. Navigate to **Project > Settings > Repository > Repository Cleanup**:
- ![Repository settings cleanup form](img/repository_cleanup.png)
+ ![Repository settings cleanup form](img/repository_cleanup.png)
- Upload the `object-id-map.old-new.txt` file and press **Start cleanup**.
- This will remove any internal git references to the old commits, and run
- `git gc` against the repository. You will receive an email once it has
- completed.
+ Upload the `object-id-map.old-new.txt` file and press **Start cleanup**.
+ This will remove any internal git references to the old commits, and run
+ `git gc` against the repository. You will receive an email once it has
+ completed.
NOTE: **Note:**
This process will remove some copies of the rewritten commits from GitLab's
@@ -110,32 +110,32 @@ purposes!
1. Navigate to your repository:
- ```
- cd my_repository/
- ```
+ ```
+ cd my_repository/
+ ```
1. Change to the branch you want to remove the big file from:
- ```
- git checkout master
- ```
+ ```
+ git checkout master
+ ```
1. Use `filter-branch` to remove the big file:
- ```
- git filter-branch --force --tree-filter 'rm -f path/to/big_file.mpg' HEAD
- ```
+ ```
+ git filter-branch --force --tree-filter 'rm -f path/to/big_file.mpg' HEAD
+ ```
1. Instruct Git to purge the unwanted data:
- ```
- git reflog expire --expire=now --all && git gc --prune=now --aggressive
- ```
+ ```
+ git reflog expire --expire=now --all && git gc --prune=now --aggressive
+ ```
1. Lastly, force push to the repository:
- ```
- git push --force origin master
- ```
+ ```
+ git push --force origin master
+ ```
Your repository should now be below the size limit.
diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md
index 253e5374f52..0116f0fe7ca 100644
--- a/doc/user/project/repository/web_editor.md
+++ b/doc/user/project/repository/web_editor.md
@@ -13,8 +13,6 @@ Choose **New file** from the dropdown.
![New file dropdown menu](img/web_editor_new_file_dropdown.png)
----
-
Enter a file name in the **File name** box. Then, add file content in the editor
area. Add a descriptive commit message and choose a branch. The branch field
will default to the branch you were viewing in the file browser. If you enter
@@ -59,8 +57,6 @@ selector. Choose **Upload file** from the dropdown.
![Upload file dropdown menu](img/web_editor_upload_file_dropdown.png)
----
-
Once the upload dialog pops up there are two ways to upload your file. Either
drag and drop a file on the pop up or use the **click to upload** link. A file
preview will appear once you have selected a file to upload.
@@ -80,8 +76,6 @@ Choose **New directory** from the dropdown.
![New directory dropdown](img/web_editor_new_directory_dropdown.png)
----
-
In the new directory dialog enter a directory name, a commit message and choose
the target branch. Click **Create directory** to finish.
@@ -129,8 +123,6 @@ choose **New branch** from the dropdown.
![New branch dropdown](img/web_editor_new_branch_dropdown.png)
----
-
Enter a new **Branch name**. Optionally, change the **Create from** field
to choose which branch, tag or commit SHA this new branch will originate from.
This field will autocomplete if you start typing an existing branch or tag.
@@ -139,8 +131,6 @@ branch.
![New branch page](img/web_editor_new_branch_page.png)
----
-
You can now make changes to any files, as needed. When you're ready to merge
the changes back to master you can use the widget at the top of the screen.
This widget only appears for a period of time after you create the branch or
@@ -156,8 +146,6 @@ SHA. From a project's files page, choose **New tag** from the dropdown.
![New tag dropdown](img/web_editor_new_tag_dropdown.png)
----
-
Give the tag a name such as `v1.0.0`. Choose the branch or SHA from which you
would like to create this new tag. You can optionally add a message and
release notes. The release notes section supports markdown format and you can
diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md
index f899120f0c2..645b9bffcc1 100644
--- a/doc/user/project/service_desk.md
+++ b/doc/user/project/service_desk.md
@@ -53,36 +53,35 @@ Service Desk is enabled on GitLab.com. If you're a
[Silver subscriber](https://about.gitlab.com/gitlab-com/),
you can skip the step 1 below; you only need to enable it per project.
-1. [Set up incoming email](../../administration/incoming_email.md#set-it-up) for the GitLab instance. This must
- support [email sub-addressing](../../administration/incoming_email.md#email-sub-addressing).
-2. Navigate to your project's **Settings** and scroll down to the **Service Desk**
- section.
-3. If you have the correct access and an Premium license,
- you will see an option to set up Service Desk:
+1. [Set up incoming email](../../administration/incoming_email.md#set-it-up) for the GitLab instance. This must
+ support [email sub-addressing](../../administration/incoming_email.md#email-sub-addressing).
+1. Navigate to your project's **Settings** and scroll down to the **Service Desk**
+ section.
+1. If you have the correct access and an Premium license,
+ you will see an option to set up Service Desk:
- ![Activate Service Desk option](img/service_desk_disabled.png)
+ ![Activate Service Desk option](img/service_desk_disabled.png)
-4. Checking that box will enable Service Desk for the project, and show a
- unique email address to email issues to the project. These issues will be
- [confidential](issues/confidential_issues.md), so they will only be visible to project members.
+1. Checking that box will enable Service Desk for the project, and show a
+ unique email address to email issues to the project. These issues will be
+ [confidential](issues/confidential_issues.md), so they will only be visible to project members.
- **Warning**: this email address can be used by anyone to create an issue on
- this project, whether or not they have access to your GitLab instance.
- We recommend **putting this behind an alias** so that it can be changed if
- needed, and **[enabling Akismet](../../integration/akismet.md)** on your GitLab instance to add spam
- checking to this service. Unblocked email spam would result in many spam
- issues being created, and may disrupt your GitLab service.
+ **Warning**: this email address can be used by anyone to create an issue on
+ this project, whether or not they have access to your GitLab instance.
+ We recommend **putting this behind an alias** so that it can be changed if
+ needed, and **[enabling Akismet](../../integration/akismet.md)** on your GitLab instance to add spam
+ checking to this service. Unblocked email spam would result in many spam
+ issues being created, and may disrupt your GitLab service.
- ![Service Desk enabled](img/service_desk_enabled.png)
+ ![Service Desk enabled](img/service_desk_enabled.png)
- _In GitLab 11.7, we updated the format of the generated email address.
- However the older format is still supported, allowing existing aliases
- or contacts to continue working._
+ _In GitLab 11.7, we updated the format of the generated email address.
+ However the older format is still supported, allowing existing aliases
+ or contacts to continue working._
+1. Service Desk is now enabled for this project! You should be able to access it from your project's navigation **Issue submenu**:
-5. Service Desk is now enabled for this project! You should be able to access it from your project's navigation **Issue submenu**:
-
- ![Service Desk Navigation Item](img/service_desk_nav_item.png)
+ ![Service Desk Navigation Item](img/service_desk_nav_item.png)
## Using Service Desk
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 98bcc7cc09f..7241df613eb 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -2,33 +2,33 @@
>**Notes:**
>
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/3050) in GitLab 8.9.
-> - Importing will not be possible if the import instance version differs from
-> that of the exporter.
-> - For GitLab admins, please read through
-> [Project import/export administration](../../../administration/raketasks/project_import_export.md).
-> - For existing installations, the project import option has to be enabled in
-> application settings (`/admin/application_settings`) under 'Import sources'.
-> Ask your administrator if you don't see the **GitLab export** button when
-> creating a new project.
-> - Starting with GitLab 10.0, administrators can disable the project export option
-> on the GitLab instance in application settings (`/admin/application_settings`)
-> under 'Visibility and Access Controls'.
-> - You can find some useful raketasks if you are an administrator in the
-> [import_export](../../../administration/raketasks/project_import_export.md) raketask.
-> - The exports are stored in a temporary [shared directory](../../../development/shared_files.md)
-> and are deleted every 24 hours by a specific worker.
-> - Group members will get exported as project members, as long as the user has
-> maintainer or admin access to the group where the exported project lives. An admin
-> in the import side is required to map the users, based on email or username.
-> Otherwise, a supplementary comment is left to mention the original author and
-> the MRs, notes or issues will be owned by the importer.
-> - Project members with owner access will get imported as maintainers.
-> - Control project Import/Export with the [API](../../../api/project_import_export.md).
-> - If an imported project contains merge requests originated from forks,
-> then new branches associated with such merge requests will be created
-> within a project during the import/export. Thus, the number of branches
-> in the exported project could be bigger than in the original project.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/3050) in GitLab 8.9.
+> - Importing will not be possible if the import instance version differs from
+> that of the exporter.
+> - For GitLab admins, please read through
+> [Project import/export administration](../../../administration/raketasks/project_import_export.md).
+> - For existing installations, the project import option has to be enabled in
+> application settings (`/admin/application_settings`) under 'Import sources'.
+> Ask your administrator if you don't see the **GitLab export** button when
+> creating a new project.
+> - Starting with GitLab 10.0, administrators can disable the project export option
+> on the GitLab instance in application settings (`/admin/application_settings`)
+> under 'Visibility and Access Controls'.
+> - You can find some useful raketasks if you are an administrator in the
+> [import_export](../../../administration/raketasks/project_import_export.md) raketask.
+> - The exports are stored in a temporary [shared directory](../../../development/shared_files.md)
+> and are deleted every 24 hours by a specific worker.
+> - Group members will get exported as project members, as long as the user has
+> maintainer or admin access to the group where the exported project lives. An admin
+> in the import side is required to map the users, based on email or username.
+> Otherwise, a supplementary comment is left to mention the original author and
+> the MRs, notes or issues will be owned by the importer.
+> - Project members with owner access will get imported as maintainers.
+> - Control project Import/Export with the [API](../../../api/project_import_export.md).
+> - If an imported project contains merge requests originated from forks,
+> then new branches associated with such merge requests will be created
+> within a project during the import/export. Thus, the number of branches
+> in the exported project could be bigger than in the original project.
Existing projects running on any GitLab instance or GitLab.com can be exported
with all their related data and be moved into a new GitLab instance.
@@ -79,7 +79,7 @@ The following items will NOT be exported:
- Awards
NOTE: **Note:**
-For more details on the specific data persisted in a project export, see the
+For more details on the specific data persisted in a project export, see the
[`import_export.yml`](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/import_export/import_export.yml) file.
## Exporting a project and its data
@@ -90,29 +90,29 @@ For more details on the specific data persisted in a project export, see the
1. Scroll down to find the **Export project** button:
- ![Export button](img/import_export_export_button.png)
+ ![Export button](img/import_export_export_button.png)
1. Once the export is generated, you should receive an e-mail with a link to
download the file:
- ![Email download link](img/import_export_mail_link.png)
+ ![Email download link](img/import_export_mail_link.png)
1. Alternatively, you can come back to the project settings and download the
file from there, or generate a new export. Once the file available, the page
should show the **Download export** button:
- ![Download export](img/import_export_download_export.png)
+ ![Download export](img/import_export_download_export.png)
## Importing the project
-1. The GitLab project import feature is the first import option when creating a
+1. The GitLab project import feature is the first import option when creating a
new project. Click on **GitLab export**:
- ![New project](img/import_export_new_project.png)
+ ![New project](img/import_export_new_project.png)
1. Enter your project name and URL. Then select the file you exported previously:
- ![Select file](img/import_export_select_file.png)
+ ![Select file](img/import_export_select_file.png)
1. Click on **Import project** to begin importing. Your newly imported project
page will appear soon.
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 06b431decad..17ec9ecb5d1 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -44,7 +44,7 @@ Set up your project's merge request settings:
- Merge request [description templates](../description_templates.md#description-templates).
- Enable [merge request approvals](../merge_requests/merge_request_approvals.md). **(STARTER)**
- Enable [merge only of pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
-- Enable [merge only when all discussions are resolved](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-discussions-are-resolved).
+- Enable [merge only when all discussions are resolved](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-threads-are-resolved).
![project's merge request settings](img/merge_requests_settings.png)
@@ -96,7 +96,7 @@ To rename a repository:
1. Hit **Rename project**.
Remember that this can have unintended side effects since everyone with the
-old URL will not be able to push or pull. Read more about what happens with the
+old URL will not be able to push or pull. Read more about what happens with the
[redirects when renaming repositories](../index.md#redirects-when-changing-repository-paths).
#### Transferring an existing project into another namespace
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index 3d92508ad04..9bf400e7dff 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -295,6 +295,5 @@ active terminal at a time.
connect to the runner. Please try to stop and restart the terminal. If the
problem persists, double check your runner configuration.
-
[ce]: https://about.gitlab.com/pricing/
[ee]: https://about.gitlab.com/pricing/
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 6ad61932868..c6396672e59 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -38,7 +38,7 @@ comments: false
- [Authorization for merge requests](../user/project/merge_requests/authorization_for_merge_requests.md)
- [Cherry-pick changes](../user/project/merge_requests/cherry_pick_changes.md)
- [Merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- - [Resolve discussion comments in merge requests reviews](../user/discussions/index.md)
+ - [Resolve threads in merge requests reviews](../user/discussions/index.md)
- [Resolve merge conflicts in the UI](../user/project/merge_requests/resolve_conflicts.md)
- [Revert changes in the UI](../user/project/merge_requests/revert_changes.md)
- [Merge requests versions](../user/project/merge_requests/versions.md)
diff --git a/doc/workflow/file_finder.md b/doc/workflow/file_finder.md
index 8d87b030c83..52c83caeea8 100644
--- a/doc/workflow/file_finder.md
+++ b/doc/workflow/file_finder.md
@@ -2,8 +2,6 @@
> [Introduced][gh-9889] in GitLab 8.4.
----
-
The file finder feature allows you to quickly shortcut your way when you are
searching for a file in a repository using the GitLab UI.
@@ -12,8 +10,6 @@ project.
![Find file button](img/file_finder_find_button.png)
----
-
For those who prefer to keep their fingers on the keyboard, there is a
[shortcut button](shortcuts.md) as well, which you can invoke from _anywhere_
in a project.
diff --git a/doc/workflow/issue_weight.md b/doc/workflow/issue_weight.md
index afb623e1967..a80519f0748 100644
--- a/doc/workflow/issue_weight.md
+++ b/doc/workflow/issue_weight.md
@@ -9,7 +9,7 @@ value or complexity a given issue has or will cost.
You can set the weight of an issue during its creation, by simply changing the
value in the dropdown menu. You can set it to a non-negative integer
-value from 0, 1, 2, and so on. (The database stores a 4-byte value, so the
+value from 0, 1, 2, and so on. (The database stores a 4-byte value, so the
upper bound is essentially limitless).
You can remove weight from an issue
as well.
diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md
index 03af8fad759..55183408a10 100644
--- a/doc/workflow/lfs/lfs_administration.md
+++ b/doc/workflow/lfs/lfs_administration.md
@@ -148,20 +148,20 @@ On Omnibus installations, the settings are prefixed by `lfs_object_store_`:
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
the values you want:
- ```ruby
- gitlab_rails['lfs_object_store_enabled'] = true
- gitlab_rails['lfs_object_store_remote_directory'] = "lfs-objects"
- gitlab_rails['lfs_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'aws_access_key_id' => '1ABCD2EFGHI34JKLM567N',
- 'aws_secret_access_key' => 'abcdefhijklmnopQRSTUVwxyz0123456789ABCDE',
- # The below options configure an S3 compatible host instead of AWS
- 'host' => 'localhost',
- 'endpoint' => 'http://127.0.0.1:9000',
- 'path_style' => true
- }
- ```
+ ```ruby
+ gitlab_rails['lfs_object_store_enabled'] = true
+ gitlab_rails['lfs_object_store_remote_directory'] = "lfs-objects"
+ gitlab_rails['lfs_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'aws_access_key_id' => '1ABCD2EFGHI34JKLM567N',
+ 'aws_secret_access_key' => 'abcdefhijklmnopQRSTUVwxyz0123456789ABCDE',
+ # The below options configure an S3 compatible host instead of AWS
+ 'host' => 'localhost',
+ 'endpoint' => 'http://127.0.0.1:9000',
+ 'path_style' => true
+ }
+ ```
1. Save the file and [reconfigure GitLab]s for the changes to take effect.
1. Migrate any existing local LFS objects to the object storage:
@@ -182,22 +182,22 @@ For source installations the settings are nested under `lfs:` and then
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- lfs:
- enabled: true
- object_store:
- enabled: false
- remote_directory: lfs-objects # Bucket name
- connection:
- provider: AWS
- aws_access_key_id: 1ABCD2EFGHI34JKLM567N
- aws_secret_access_key: abcdefhijklmnopQRSTUVwxyz0123456789ABCDE
- region: eu-central-1
- # Use the following options to configure an AWS compatible host such as Minio
- host: 'localhost'
- endpoint: 'http://127.0.0.1:9000'
- path_style: true
- ```
+ ```yaml
+ lfs:
+ enabled: true
+ object_store:
+ enabled: false
+ remote_directory: lfs-objects # Bucket name
+ connection:
+ provider: AWS
+ aws_access_key_id: 1ABCD2EFGHI34JKLM567N
+ aws_secret_access_key: abcdefhijklmnopQRSTUVwxyz0123456789ABCDE
+ region: eu-central-1
+ # Use the following options to configure an AWS compatible host such as Minio
+ host: 'localhost'
+ endpoint: 'http://127.0.0.1:9000'
+ path_style: true
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Migrate any existing local LFS objects to the object storage:
diff --git a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
index 202f2e39975..b6bba57049d 100644
--- a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
+++ b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
@@ -250,7 +250,7 @@ If you are storing LFS files outside of GitLab you can disable LFS on the projec
It is possible to host LFS objects externally by setting a custom LFS url with `git config -f .lfsconfig lfs.url https://example.com/<project>.git/info/lfs`.
-You might choose to do this if you are using an appliance like a Sonatype Nexus to store LFS data. If you choose to use an external LFS store,
+You might choose to do this if you are using an appliance like a Sonatype Nexus to store LFS data. If you choose to use an external LFS store,
GitLab will not be able to verify LFS objects which means that pushes will fail if you have GitLab LFS support enabled.
To stop push failure, LFS support can be disabled in the [Project settings](../../user/project/settings/index.md). This means you will lose GitLab LFS value-adds (Verifying LFS objects, UI integration for LFS).
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
index 1e8674f863d..d82f7c6fdc7 100644
--- a/doc/workflow/notifications.md
+++ b/doc/workflow/notifications.md
@@ -138,7 +138,7 @@ Notification emails include headers that provide extra content about the notific
| X-GitLab-Project-Id | The ID of the project |
| X-GitLab-Project-Path | The path of the project |
| X-GitLab-(Resource)-ID | The ID of the resource the notification is for, where resource is `Issue`, `MergeRequest`, `Commit`, etc|
-| X-GitLab-Discussion-ID | Only in comment emails, the ID of the discussion the comment is from |
+| X-GitLab-Discussion-ID | Only in comment emails, the ID of the thread the comment is from |
| X-GitLab-Pipeline-Id | Only in pipeline emails, the ID of the pipeline the notification is for |
| X-GitLab-Reply-Key | A unique token to support reply by email |
| X-GitLab-NotificationReason | The reason for being notified. "mentioned", "assigned", etc |
diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md
index 1f8900c734b..0432c406f31 100644
--- a/doc/workflow/todos.md
+++ b/doc/workflow/todos.md
@@ -12,8 +12,6 @@ in a simple dashboard.
![To Do screenshot showing a list of items to check on](img/todos_index.png)
----
-
You can quickly access your To-Do List by clicking the checkmark icon next to the
search bar in the top navigation. If the count is:
@@ -31,15 +29,15 @@ A To Do displays on your To-Do List when:
- An issue or merge request is assigned to you
- You are `@mentioned` in the description or comment of an:
- - Issue
- - Merge Request
- - Epic **(ULTIMATE)**
+ - Issue
+ - Merge Request
+ - Epic **(ULTIMATE)**
- You are `@mentioned` in a comment on a commit
- A job in the CI pipeline running for your merge request failed, but this
job is not allowed to fail
- An open merge request becomes unmergeable due to conflict, and you are either:
- - The author
- - Have set it to automatically merge once the pipeline succeeds
+ - The author
+ - Have set it to automatically merge once the pipeline succeeds
To-do triggers are not affected by [GitLab Notification Email settings](notifications.md).
@@ -94,8 +92,6 @@ Actions that dismiss To-Do items include:
- Adding/removing a label
- Commenting on the issue
----
-
Your To-Do List is personal, and items are only marked as done if the action comes from
you. If you close the issue or merge request, your To Do is automatically
marked as done.
@@ -108,8 +104,6 @@ To prevent other users from closing issues without you being notified, if someon
There is just one To Do for each of these, so mentioning a user a hundred times in an issue will only trigger one To Do.
----
-
If no action is needed, you can manually mark the To Do as done by clicking the
corresponding **Done** button, and it will disappear from your To-Do List.
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 7016a66593d..223ae13bd2d 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -10,13 +10,14 @@ module API
NAMESPACE_OR_PROJECT_REQUIREMENTS = { id: NO_SLASH_URL_PART_REGEX }.freeze
COMMIT_ENDPOINT_REQUIREMENTS = NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(sha: NO_SLASH_URL_PART_REGEX).freeze
USER_REQUIREMENTS = { user_id: NO_SLASH_URL_PART_REGEX }.freeze
+ LOG_FILTERS = ::Rails.application.config.filter_parameters + [/^output$/]
insert_before Grape::Middleware::Error,
GrapeLogging::Middleware::RequestLogger,
logger: Logger.new(LOG_FILENAME),
formatter: Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new,
include: [
- GrapeLogging::Loggers::FilterParameters.new,
+ GrapeLogging::Loggers::FilterParameters.new(LOG_FILTERS),
GrapeLogging::Loggers::ClientEnv.new,
Gitlab::GrapeLogging::Loggers::RouteLogger.new,
Gitlab::GrapeLogging::Loggers::UserLogger.new,
@@ -111,6 +112,7 @@ module API
mount ::API::Features
mount ::API::Files
mount ::API::GroupBoards
+ mount ::API::GroupClusters
mount ::API::GroupLabels
mount ::API::GroupMilestones
mount ::API::Groups
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index eebded87ebc..c414ad75d9d 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -126,7 +126,7 @@ module API
if result[:status] == :success
commit_detail = user_project.repository.commit(result[:result])
- Gitlab::WebIdeCommitsCounter.increment if find_user_from_warden
+ Gitlab::UsageDataCounters::WebIdeCommitsCounter.increment if find_user_from_warden
present commit_detail, with: Entities::CommitDetail, stats: params[:stats]
else
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 765819e6bf1..0a9515f1dd2 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1686,5 +1686,9 @@ module API
class ClusterProject < Cluster
expose :project, using: Entities::BasicProjectDetails
end
+
+ class ClusterGroup < Cluster
+ expose :group, using: Entities::BasicGroupDetails
+ end
end
end
diff --git a/lib/api/group_clusters.rb b/lib/api/group_clusters.rb
new file mode 100644
index 00000000000..db0f8081140
--- /dev/null
+++ b/lib/api/group_clusters.rb
@@ -0,0 +1,140 @@
+# frozen_string_literal: true
+
+module API
+ class GroupClusters < Grape::API
+ include PaginationParams
+
+ before { authenticate! }
+
+ # EE::API::GroupClusters will
+ # override these methods
+ helpers do
+ params :create_params_ee do
+ end
+
+ params :update_params_ee do
+ end
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of the group'
+ end
+ resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ desc 'Get all clusters from the group' do
+ success Entities::Cluster
+ end
+ params do
+ use :pagination
+ end
+ get ':id/clusters' do
+ authorize! :read_cluster, user_group
+
+ present paginate(clusters_for_current_user), with: Entities::Cluster
+ end
+
+ desc 'Get specific cluster for the group' do
+ success Entities::ClusterGroup
+ end
+ params do
+ requires :cluster_id, type: Integer, desc: 'The cluster ID'
+ end
+ get ':id/clusters/:cluster_id' do
+ authorize! :read_cluster, cluster
+
+ present cluster, with: Entities::ClusterGroup
+ end
+
+ desc 'Adds an existing cluster' do
+ success Entities::ClusterGroup
+ end
+ params do
+ requires :name, type: String, desc: 'Cluster name'
+ optional :enabled, type: Boolean, default: true, desc: 'Determines if cluster is active or not, defaults to true'
+ optional :domain, type: String, desc: 'Cluster base domain'
+ optional :managed, type: Boolean, default: true, desc: 'Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true'
+ requires :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
+ requires :api_url, type: String, allow_blank: false, desc: 'URL to access the Kubernetes API'
+ requires :token, type: String, desc: 'Token to authenticate against Kubernetes'
+ optional :ca_cert, type: String, desc: 'TLS certificate (needed if API is using a self-signed TLS certificate)'
+ optional :namespace, type: String, desc: 'Unique namespace related to Group'
+ optional :authorization_type, type: String, values: Clusters::Platforms::Kubernetes.authorization_types.keys, default: 'rbac', desc: 'Cluster authorization type, defaults to RBAC'
+ end
+ use :create_params_ee
+ end
+ post ':id/clusters/user' do
+ authorize! :add_cluster, user_group
+
+ user_cluster = ::Clusters::CreateService
+ .new(current_user, create_cluster_user_params)
+ .execute
+
+ if user_cluster.persisted?
+ present user_cluster, with: Entities::ClusterGroup
+ else
+ render_validation_error!(user_cluster)
+ end
+ end
+
+ desc 'Update an existing cluster' do
+ success Entities::ClusterGroup
+ end
+ params do
+ requires :cluster_id, type: Integer, desc: 'The cluster ID'
+ optional :name, type: String, desc: 'Cluster name'
+ optional :domain, type: String, desc: 'Cluster base domain'
+ optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
+ optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
+ optional :token, type: String, desc: 'Token to authenticate against Kubernetes'
+ optional :ca_cert, type: String, desc: 'TLS certificate (needed if API is using a self-signed TLS certificate)'
+ optional :namespace, type: String, desc: 'Unique namespace related to Group'
+ end
+ use :update_params_ee
+ end
+ put ':id/clusters/:cluster_id' do
+ authorize! :update_cluster, cluster
+
+ update_service = Clusters::UpdateService.new(current_user, update_cluster_params)
+
+ if update_service.execute(cluster)
+ present cluster, with: Entities::ClusterGroup
+ else
+ render_validation_error!(cluster)
+ end
+ end
+
+ desc 'Remove a cluster' do
+ success Entities::ClusterGroup
+ end
+ params do
+ requires :cluster_id, type: Integer, desc: 'The Cluster ID'
+ end
+ delete ':id/clusters/:cluster_id' do
+ authorize! :admin_cluster, cluster
+
+ destroy_conditionally!(cluster)
+ end
+ end
+
+ helpers do
+ def clusters_for_current_user
+ @clusters_for_current_user ||= ClustersFinder.new(user_group, current_user, :all).execute
+ end
+
+ def cluster
+ @cluster ||= clusters_for_current_user.find(params[:cluster_id])
+ end
+
+ def create_cluster_user_params
+ declared_params.merge({
+ provider_type: :user,
+ platform_type: :kubernetes,
+ clusterable: user_group
+ })
+ end
+
+ def update_cluster_params
+ declared_params(include_missing: false).without(:cluster_id)
+ end
+ end
+ end
+end
diff --git a/lib/api/helpers/pagination.rb b/lib/api/helpers/pagination.rb
index 2a9b17ad22a..71bbc218f94 100644
--- a/lib/api/helpers/pagination.rb
+++ b/lib/api/helpers/pagination.rb
@@ -205,7 +205,9 @@ module API
limited_total_count = pagination_data.total_count_with_limit
if limited_total_count > Kaminari::ActiveRecordRelationMethods::MAX_COUNT_LIMIT
- pagination_data.without_count
+ # The call to `total_count_with_limit` memoizes `@arel` because of a call to `references_eager_loaded_tables?`
+ # We need to call `reset` because `without_count` relies on `@arel` being unmemoized
+ pagination_data.reset.without_count
else
pagination_data
end
diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb
index ff73a49d5e8..100463fcb95 100644
--- a/lib/api/helpers/runner.rb
+++ b/lib/api/helpers/runner.rb
@@ -7,8 +7,7 @@ module API
JOB_TOKEN_PARAM = :token
def runner_registration_token_valid?
- ActiveSupport::SecurityUtils.variable_size_secure_compare(params[:token],
- Gitlab::CurrentSettings.runners_registration_token)
+ ActiveSupport::SecurityUtils.secure_compare(params[:token], Gitlab::CurrentSettings.runners_registration_token)
end
def authenticate_runner!
diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb
index dcc8d94fb79..4f093e9be08 100644
--- a/lib/api/project_clusters.rb
+++ b/lib/api/project_clusters.rb
@@ -65,7 +65,7 @@ module API
use :create_params_ee
end
post ':id/clusters/user' do
- authorize! :add_cluster, user_project, 'Instance does not support multiple Kubernetes clusters'
+ authorize! :add_cluster, user_project
user_cluster = ::Clusters::CreateService
.new(current_user, create_cluster_user_params)
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index fdd8406388e..7a3d804c30c 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -78,7 +78,7 @@ module API
requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
optional :name, type: String, desc: 'The name of the release'
optional :description, type: String, desc: 'Release notes with markdown support'
- optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
+ optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready.'
end
put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
authorize_update_release!
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 41418aa216c..30a278fdff1 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -51,7 +51,7 @@ module API
optional :can_create_group, type: Boolean, desc: 'Flag indicating the user can create groups'
optional :external, type: Boolean, desc: 'Flag indicating the user is an external user'
optional :avatar, type: File, desc: 'Avatar image for user'
- optional :private_profile, type: Boolean, desc: 'Flag indicating the user has a private profile'
+ optional :private_profile, type: Boolean, default: false, desc: 'Flag indicating the user has a private profile'
all_or_none_of :extern_uid, :provider
use :optional_params_ee
diff --git a/lib/banzai/filter/ascii_doc_sanitization_filter.rb b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
new file mode 100644
index 00000000000..d8d63075752
--- /dev/null
+++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Banzai
+ module Filter
+ # Sanitize HTML produced by AsciiDoc/Asciidoctor.
+ #
+ # Extends Banzai::Filter::BaseSanitizationFilter with specific rules.
+ class AsciiDocSanitizationFilter < Banzai::Filter::BaseSanitizationFilter
+ # Section anchor link pattern
+ SECTION_LINK_REF_PATTERN = /\A#{Gitlab::Asciidoc::DEFAULT_ADOC_ATTRS['idprefix']}(:?[[:alnum:]]|-|_)+\z/.freeze
+
+ # Classes used by Asciidoctor to style components
+ ADMONITION_CLASSES = %w(fa icon-note icon-tip icon-warning icon-caution icon-important).freeze
+ CALLOUT_CLASSES = ['conum'].freeze
+ CHECKLIST_CLASSES = %w(fa fa-check-square-o fa-square-o).freeze
+
+ LIST_CLASSES = %w(checklist none no-bullet unnumbered unstyled).freeze
+
+ ELEMENT_CLASSES_WHITELIST = {
+ span: %w(big small underline overline line-through).freeze,
+ div: ['admonitionblock'].freeze,
+ td: ['icon'].freeze,
+ i: ADMONITION_CLASSES + CALLOUT_CLASSES + CHECKLIST_CLASSES,
+ ul: LIST_CLASSES,
+ ol: LIST_CLASSES,
+ a: ['anchor'].freeze
+ }.freeze
+
+ ALLOWED_HEADERS = %w(h2 h3 h4 h5 h6).freeze
+
+ def customize_whitelist(whitelist)
+ # Allow marks
+ whitelist[:elements].push('mark')
+
+ # Allow any classes in `span`, `i`, `div`, `td`, `ul`, `ol` and `a` elements
+ # but then remove any unknown classes
+ whitelist[:attributes]['span'] = %w(class)
+ whitelist[:attributes]['div'].push('class')
+ whitelist[:attributes]['td'] = %w(class)
+ whitelist[:attributes]['i'] = %w(class)
+ whitelist[:attributes]['ul'] = %w(class)
+ whitelist[:attributes]['ol'] = %w(class)
+ whitelist[:attributes]['a'].push('class')
+ whitelist[:transformers].push(self.class.remove_element_classes)
+
+ # Allow `id` in heading elements for section anchors
+ ALLOWED_HEADERS.each do |header|
+ whitelist[:attributes][header] = %w(id)
+ end
+ whitelist[:transformers].push(self.class.remove_non_heading_ids)
+
+ whitelist
+ end
+
+ class << self
+ def remove_non_heading_ids
+ lambda do |env|
+ node = env[:node]
+
+ return unless ALLOWED_HEADERS.any?(node.name)
+ return unless node.has_attribute?('id')
+
+ return if node['id'] =~ SECTION_LINK_REF_PATTERN
+
+ node.remove_attribute('id')
+ end
+ end
+
+ def remove_element_classes
+ lambda do |env|
+ node = env[:node]
+
+ return unless (classes_whitelist = ELEMENT_CLASSES_WHITELIST[node.name.to_sym])
+ return unless node.has_attribute?('class')
+
+ classes = node['class'].strip.split(' ')
+ allowed_classes = (classes & classes_whitelist)
+ if allowed_classes.empty?
+ node.remove_attribute('class')
+ else
+ node['class'] = allowed_classes.join(' ')
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/base_sanitization_filter.rb b/lib/banzai/filter/base_sanitization_filter.rb
new file mode 100644
index 00000000000..420e92cb1e8
--- /dev/null
+++ b/lib/banzai/filter/base_sanitization_filter.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+module Banzai
+ module Filter
+ # Sanitize HTML produced by markup languages (Markdown, AsciiDoc...).
+ # Specific rules are implemented in dedicated filters:
+ #
+ # - Banzai::Filter::SanitizationFilter (Markdown)
+ # - Banzai::Filter::AsciiDocSanitizationFilter (AsciiDoc/Asciidoctor)
+ #
+ # Extends HTML::Pipeline::SanitizationFilter with common rules.
+ class BaseSanitizationFilter < HTML::Pipeline::SanitizationFilter
+ include Gitlab::Utils::StrongMemoize
+
+ UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze
+
+ def whitelist
+ strong_memoize(:whitelist) do
+ whitelist = super.deep_dup
+
+ # Allow span elements
+ whitelist[:elements].push('span')
+
+ # Allow data-math-style attribute in order to support LaTeX formatting
+ whitelist[:attributes]['code'] = %w(data-math-style)
+ whitelist[:attributes]['pre'] = %w(data-math-style)
+
+ # Allow html5 details/summary elements
+ whitelist[:elements].push('details')
+ whitelist[:elements].push('summary')
+
+ # Allow abbr elements with title attribute
+ whitelist[:elements].push('abbr')
+ whitelist[:attributes]['abbr'] = %w(title)
+
+ # Disallow `name` attribute globally, allow on `a`
+ whitelist[:attributes][:all].delete('name')
+ whitelist[:attributes]['a'].push('name')
+
+ # Allow any protocol in `a` elements
+ # and then remove links with unsafe protocols
+ whitelist[:protocols].delete('a')
+ whitelist[:transformers].push(self.class.remove_unsafe_links)
+
+ # Remove `rel` attribute from `a` elements
+ whitelist[:transformers].push(self.class.remove_rel)
+
+ customize_whitelist(whitelist)
+ end
+ end
+
+ def customize_whitelist(whitelist)
+ raise NotImplementedError
+ end
+
+ class << self
+ def remove_unsafe_links
+ lambda do |env|
+ node = env[:node]
+
+ return unless node.name == 'a'
+ return unless node.has_attribute?('href')
+
+ begin
+ node['href'] = node['href'].strip
+ uri = Addressable::URI.parse(node['href'])
+
+ return unless uri.scheme
+
+ # Remove all invalid scheme characters before checking against the
+ # list of unsafe protocols.
+ #
+ # See https://tools.ietf.org/html/rfc3986#section-3.1
+ scheme = uri.scheme
+ .strip
+ .downcase
+ .gsub(/[^A-Za-z0-9\+\.\-]+/, '')
+
+ node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(scheme)
+ rescue Addressable::URI::InvalidURIError
+ node.remove_attribute('href')
+ end
+ end
+ end
+
+ def remove_rel
+ lambda do |env|
+ if env[:node_name] == 'a'
+ env[:node].remove_attribute('rel')
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/redactor_filter.rb b/lib/banzai/filter/reference_redactor_filter.rb
index 1f091f594f8..485d3fd5fc7 100644
--- a/lib/banzai/filter/redactor_filter.rb
+++ b/lib/banzai/filter/reference_redactor_filter.rb
@@ -7,12 +7,12 @@ module Banzai
#
# Expected to be run in its own post-processing pipeline.
#
- class RedactorFilter < HTML::Pipeline::Filter
+ class ReferenceRedactorFilter < HTML::Pipeline::Filter
def call
unless context[:skip_redaction]
context = RenderContext.new(project, current_user)
- Redactor.new(context).redact([doc])
+ ReferenceRedactor.new(context).redact([doc])
end
doc
diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb
index a4a06eae7b7..f57e57890f8 100644
--- a/lib/banzai/filter/sanitization_filter.rb
+++ b/lib/banzai/filter/sanitization_filter.rb
@@ -2,23 +2,13 @@
module Banzai
module Filter
- # Sanitize HTML
+ # Sanitize HTML produced by Markdown.
#
- # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
- class SanitizationFilter < HTML::Pipeline::SanitizationFilter
- include Gitlab::Utils::StrongMemoize
-
- UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze
+ # Extends Banzai::Filter::BaseSanitizationFilter with specific rules.
+ class SanitizationFilter < Banzai::Filter::BaseSanitizationFilter
+ # Styles used by Markdown for table alignment
TABLE_ALIGNMENT_PATTERN = /text-align: (?<alignment>center|left|right)/.freeze
- def whitelist
- strong_memoize(:whitelist) do
- customize_whitelist(super.deep_dup)
- end
- end
-
- private
-
def customize_whitelist(whitelist)
# Allow table alignment; we whitelist specific text-align values in a
# transformer below
@@ -26,36 +16,9 @@ module Banzai
whitelist[:attributes]['td'] = %w(style)
whitelist[:css] = { properties: ['text-align'] }
- # Allow span elements
- whitelist[:elements].push('span')
-
- # Allow data-math-style attribute in order to support LaTeX formatting
- whitelist[:attributes]['code'] = %w(data-math-style)
- whitelist[:attributes]['pre'] = %w(data-math-style)
-
- # Allow html5 details/summary elements
- whitelist[:elements].push('details')
- whitelist[:elements].push('summary')
-
- # Allow abbr elements with title attribute
- whitelist[:elements].push('abbr')
- whitelist[:attributes]['abbr'] = %w(title)
-
# Allow the 'data-sourcepos' from CommonMark on all elements
whitelist[:attributes][:all].push('data-sourcepos')
- # Disallow `name` attribute globally, allow on `a`
- whitelist[:attributes][:all].delete('name')
- whitelist[:attributes]['a'].push('name')
-
- # Allow any protocol in `a` elements
- # and then remove links with unsafe protocols
- whitelist[:protocols].delete('a')
- whitelist[:transformers].push(self.class.remove_unsafe_links)
-
- # Remove `rel` attribute from `a` elements
- whitelist[:transformers].push(self.class.remove_rel)
-
# Remove any `style` properties not required for table alignment
whitelist[:transformers].push(self.class.remove_unsafe_table_style)
@@ -69,43 +32,6 @@ module Banzai
end
class << self
- def remove_unsafe_links
- lambda do |env|
- node = env[:node]
-
- return unless node.name == 'a'
- return unless node.has_attribute?('href')
-
- begin
- node['href'] = node['href'].strip
- uri = Addressable::URI.parse(node['href'])
-
- return unless uri.scheme
-
- # Remove all invalid scheme characters before checking against the
- # list of unsafe protocols.
- #
- # See https://tools.ietf.org/html/rfc3986#section-3.1
- scheme = uri.scheme
- .strip
- .downcase
- .gsub(/[^A-Za-z0-9\+\.\-]+/, '')
-
- node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(scheme)
- rescue Addressable::URI::InvalidURIError
- node.remove_attribute('href')
- end
- end
- end
-
- def remove_rel
- lambda do |env|
- if env[:node_name] == 'a'
- env[:node].remove_attribute('rel')
- end
- end
- end
-
def remove_unsafe_table_style
lambda do |env|
node = env[:node]
diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb
index 75661ffa233..d6d29f4bfab 100644
--- a/lib/banzai/object_renderer.rb
+++ b/lib/banzai/object_renderer.rb
@@ -72,7 +72,7 @@ module Banzai
#
# Returns an Array containing the redacted documents.
def redact_documents(documents)
- redactor = Redactor.new(context)
+ redactor = ReferenceRedactor.new(context)
redactor.redact(documents)
end
diff --git a/lib/banzai/pipeline/ascii_doc_pipeline.rb b/lib/banzai/pipeline/ascii_doc_pipeline.rb
index 6be489c6572..d25b74b23b2 100644
--- a/lib/banzai/pipeline/ascii_doc_pipeline.rb
+++ b/lib/banzai/pipeline/ascii_doc_pipeline.rb
@@ -5,7 +5,7 @@ module Banzai
class AsciiDocPipeline < BasePipeline
def self.filters
FilterArray[
- Filter::SanitizationFilter,
+ Filter::AsciiDocSanitizationFilter,
Filter::SyntaxHighlightFilter,
Filter::ExternalLinkFilter,
Filter::PlantumlFilter,
diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb
index 5c199453638..54af26b41be 100644
--- a/lib/banzai/pipeline/post_process_pipeline.rb
+++ b/lib/banzai/pipeline/post_process_pipeline.rb
@@ -12,7 +12,7 @@ module Banzai
def self.internal_link_filters
[
- Filter::RedactorFilter,
+ Filter::ReferenceRedactorFilter,
Filter::InlineMetricsRedactorFilter,
Filter::RelativeLinkFilter,
Filter::IssuableStateFilter,
diff --git a/lib/banzai/redactor.rb b/lib/banzai/reference_redactor.rb
index c2da7fec7cc..eb5c35da375 100644
--- a/lib/banzai/redactor.rb
+++ b/lib/banzai/reference_redactor.rb
@@ -3,7 +3,7 @@
module Banzai
# Class for removing Markdown references a certain user is not allowed to
# view.
- class Redactor
+ class ReferenceRedactor
attr_reader :context
# context - An instance of `Banzai::RenderContext`.
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
index 81f32ef5bcf..3cb9ec21e8f 100644
--- a/lib/banzai/renderer.rb
+++ b/lib/banzai/renderer.rb
@@ -134,7 +134,7 @@ module Banzai
#
# This method is used to perform state-dependent changes to a String of
# HTML, such as removing references that the current user doesn't have
- # permission to make (`RedactorFilter`).
+ # permission to make (`ReferenceRedactorFilter`).
#
# html - String to process
# context - Hash of options to customize output
diff --git a/lib/feature/gitaly.rb b/lib/feature/gitaly.rb
index 67c0b902c0c..edfd2fb17f3 100644
--- a/lib/feature/gitaly.rb
+++ b/lib/feature/gitaly.rb
@@ -5,16 +5,12 @@ require 'set'
class Feature
class Gitaly
# Server feature flags should use '_' to separate words.
- # CATFILE_CACHE sets an incorrect example
- CATFILE_CACHE = 'catfile-cache'.freeze
-
SERVER_FEATURE_FLAGS =
[
- CATFILE_CACHE,
'get_commit_signatures'.freeze
].freeze
- DEFAULT_ON_FLAGS = Set.new([CATFILE_CACHE]).freeze
+ DEFAULT_ON_FLAGS = Set.new([]).freeze
class << self
def enabled?(feature_flag)
diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb
index 00c87cce7b6..da65caa6c9c 100644
--- a/lib/gitlab/asciidoc.rb
+++ b/lib/gitlab/asciidoc.rb
@@ -13,6 +13,7 @@ module Gitlab
MAX_INCLUDE_DEPTH = 5
DEFAULT_ADOC_ATTRS = {
'showtitle' => true,
+ 'sectanchors' => true,
'idprefix' => 'user-content-',
'idseparator' => '-',
'env' => 'gitlab',
diff --git a/lib/gitlab/background_migration/fix_user_namespace_names.rb b/lib/gitlab/background_migration/fix_user_namespace_names.rb
new file mode 100644
index 00000000000..1a207121be0
--- /dev/null
+++ b/lib/gitlab/background_migration/fix_user_namespace_names.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # This migration fixes the namespaces.name for all user-namespaces that have names
+ # that aren't equal to the users name.
+ # Then it uses the updated names of the namespaces to update the associated routes
+ # For more info see https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23272
+ class FixUserNamespaceNames
+ def perform(from_id, to_id)
+ fix_namespace_names(from_id, to_id)
+ fix_namespace_route_names(from_id, to_id)
+ end
+
+ def fix_namespace_names(from_id, to_id)
+ ActiveRecord::Base.connection.execute <<~UPDATE_NAMESPACES
+ WITH namespaces_to_update AS (
+ SELECT
+ namespaces.id,
+ users.name AS correct_name
+ FROM
+ namespaces
+ INNER JOIN users ON namespaces.owner_id = users.id
+ WHERE
+ namespaces.type IS NULL
+ AND namespaces.id BETWEEN #{from_id} AND #{to_id}
+ AND namespaces.name != users.name
+ )
+ UPDATE
+ namespaces
+ SET
+ name = correct_name
+ FROM
+ namespaces_to_update
+ WHERE
+ namespaces.id = namespaces_to_update.id
+ UPDATE_NAMESPACES
+ end
+
+ def fix_namespace_route_names(from_id, to_id)
+ ActiveRecord::Base.connection.execute <<~ROUTES_UPDATE
+ WITH routes_to_update AS (
+ SELECT
+ routes.id,
+ users.name AS correct_name
+ FROM
+ routes
+ INNER JOIN namespaces ON routes.source_id = namespaces.id
+ INNER JOIN users ON namespaces.owner_id = users.id
+ WHERE
+ namespaces.type IS NULL
+ AND routes.source_type = 'Namespace'
+ AND namespaces.id BETWEEN #{from_id} AND #{to_id}
+ AND (routes.name != users.name OR routes.name IS NULL)
+ )
+ UPDATE
+ routes
+ SET
+ name = correct_name
+ FROM
+ routes_to_update
+ WHERE
+ routes_to_update.id = routes.id
+ ROUTES_UPDATE
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/fix_user_project_route_names.rb b/lib/gitlab/background_migration/fix_user_project_route_names.rb
new file mode 100644
index 00000000000..b84ff32e712
--- /dev/null
+++ b/lib/gitlab/background_migration/fix_user_project_route_names.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # This migration fixes the routes.name for all user-projects that have names
+ # that don't start with the users name.
+ # For more info see https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23272
+ class FixUserProjectRouteNames
+ def perform(from_id, to_id)
+ ActiveRecord::Base.connection.execute <<~ROUTES_UPDATE
+ WITH routes_to_update AS (
+ SELECT
+ routes.id,
+ users.name || ' / ' || projects.name AS correct_name
+ FROM
+ routes
+ INNER JOIN projects ON routes.source_id = projects.id
+ INNER JOIN namespaces ON projects.namespace_id = namespaces.id
+ INNER JOIN users ON namespaces.owner_id = users.id
+ WHERE
+ routes.source_type = 'Project'
+ AND routes.id BETWEEN #{from_id} AND #{to_id}
+ AND namespaces.type IS NULL
+ AND (routes.name NOT LIKE users.name || '%' OR routes.name IS NULL)
+ )
+ UPDATE
+ routes
+ SET
+ name = routes_to_update.correct_name
+ FROM
+ routes_to_update
+ WHERE
+ routes_to_update.id = routes.id
+ ROUTES_UPDATE
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/migrate_null_private_profile_to_false.rb b/lib/gitlab/background_migration/migrate_null_private_profile_to_false.rb
new file mode 100644
index 00000000000..32ed6a2756d
--- /dev/null
+++ b/lib/gitlab/background_migration/migrate_null_private_profile_to_false.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # This class is responsible for migrating a range of users with private_profile == NULL to false
+ class MigrateNullPrivateProfileToFalse
+ # Temporary AR class for users
+ class User < ActiveRecord::Base
+ self.table_name = 'users'
+ end
+
+ def perform(start_id, stop_id)
+ User.where(private_profile: nil, id: start_id..stop_id).update_all(private_profile: false)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/populate_merge_request_assignees_table.rb b/lib/gitlab/background_migration/populate_merge_request_assignees_table.rb
index a4c6540c61b..eb4bc0aaf28 100644
--- a/lib/gitlab/background_migration/populate_merge_request_assignees_table.rb
+++ b/lib/gitlab/background_migration/populate_merge_request_assignees_table.rb
@@ -18,6 +18,14 @@ module Gitlab
execute("INSERT INTO merge_request_assignees (merge_request_id, user_id) #{select_sql}")
end
+ def perform_all_sync(batch_size:)
+ MergeRequest.each_batch(of: batch_size) do |batch|
+ range = batch.pluck('MIN(id)', 'MAX(id)').first
+
+ perform(*range)
+ end
+ end
+
private
def merge_request_assignees_not_exists_clause
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index c911bfa7ff6..afad391e8e0 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -20,6 +20,12 @@ module Gitlab
end
end
+ def uses_unsupported_legacy_trigger?
+ trigger_request.present? &&
+ trigger_request.trigger.legacy? &&
+ !trigger_request.trigger.supports_legacy_tokens?
+ end
+
def branch_exists?
strong_memoize(:is_branch) do
project.repository.branch_exists?(ref)
diff --git a/lib/gitlab/ci/pipeline/chain/validate/abilities.rb b/lib/gitlab/ci/pipeline/chain/validate/abilities.rb
index aaa3daddcc5..357a1d55b3b 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/abilities.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/abilities.rb
@@ -14,6 +14,10 @@ module Gitlab
return error('Pipelines are disabled!')
end
+ if @command.uses_unsupported_legacy_trigger?
+ return error('Trigger token is invalid because is not owned by any user')
+ end
+
unless allowed_to_trigger_pipeline?
if can?(current_user, :create_pipeline, project)
return error("Insufficient permissions for protected ref '#{command.ref}'")
diff --git a/lib/gitlab/ci/pipeline/expression/lexeme/pattern.rb b/lib/gitlab/ci/pipeline/expression/lexeme/pattern.rb
index e4cf360a1c1..0212fa9d661 100644
--- a/lib/gitlab/ci/pipeline/expression/lexeme/pattern.rb
+++ b/lib/gitlab/ci/pipeline/expression/lexeme/pattern.rb
@@ -8,11 +8,10 @@ module Gitlab
require_dependency 're2'
class Pattern < Lexeme::Value
- PATTERN = %r{^/.+/[ismU]*$}.freeze
- NEW_PATTERN = %r{^\/([^\/]|\\/)+[^\\]\/[ismU]*}.freeze
+ PATTERN = %r{^\/([^\/]|\\/)+[^\\]\/[ismU]*}.freeze
def initialize(regexp)
- @value = self.class.eager_matching_with_escape_characters? ? regexp.gsub(/\\\//, '/') : regexp
+ @value = regexp.gsub(/\\\//, '/')
unless Gitlab::UntrustedRegexp::RubySyntax.valid?(@value)
raise Lexer::SyntaxError, 'Invalid regular expression!'
@@ -26,16 +25,12 @@ module Gitlab
end
def self.pattern
- eager_matching_with_escape_characters? ? NEW_PATTERN : PATTERN
+ PATTERN
end
def self.build(string)
new(string)
end
-
- def self.eager_matching_with_escape_characters?
- Feature.enabled?(:ci_variables_complex_expressions, default_enabled: true)
- end
end
end
end
diff --git a/lib/gitlab/ci/pipeline/expression/lexer.rb b/lib/gitlab/ci/pipeline/expression/lexer.rb
index 22c210ae26b..7d7582612f9 100644
--- a/lib/gitlab/ci/pipeline/expression/lexer.rb
+++ b/lib/gitlab/ci/pipeline/expression/lexer.rb
@@ -17,17 +17,6 @@ module Gitlab
Expression::Lexeme::Equals,
Expression::Lexeme::Matches,
Expression::Lexeme::NotEquals,
- Expression::Lexeme::NotMatches
- ].freeze
-
- NEW_LEXEMES = [
- Expression::Lexeme::Variable,
- Expression::Lexeme::String,
- Expression::Lexeme::Pattern,
- Expression::Lexeme::Null,
- Expression::Lexeme::Equals,
- Expression::Lexeme::Matches,
- Expression::Lexeme::NotEquals,
Expression::Lexeme::NotMatches,
Expression::Lexeme::And,
Expression::Lexeme::Or
@@ -58,7 +47,7 @@ module Gitlab
return tokens if @scanner.eos?
- lexeme = available_lexemes.find do |type|
+ lexeme = LEXEMES.find do |type|
type.scan(@scanner).tap do |token|
tokens.push(token) if token.present?
end
@@ -71,10 +60,6 @@ module Gitlab
raise Lexer::SyntaxError, 'Too many tokens!'
end
-
- def available_lexemes
- Feature.enabled?(:ci_variables_complex_expressions, default_enabled: true) ? NEW_LEXEMES : LEXEMES
- end
end
end
end
diff --git a/lib/gitlab/ci/pipeline/expression/parser.rb b/lib/gitlab/ci/pipeline/expression/parser.rb
index 589bf32a4d7..edb55edf356 100644
--- a/lib/gitlab/ci/pipeline/expression/parser.rb
+++ b/lib/gitlab/ci/pipeline/expression/parser.rb
@@ -13,39 +13,6 @@ module Gitlab
end
def tree
- if Feature.enabled?(:ci_variables_complex_expressions, default_enabled: true)
- rpn_parse_tree
- else
- reverse_descent_parse_tree
- end
- end
-
- def self.seed(statement)
- new(Expression::Lexer.new(statement).tokens)
- end
-
- private
-
- # This produces a reverse descent parse tree.
- # It does not support precedence of operators.
- def reverse_descent_parse_tree
- while token = @tokens.next
- case token.type
- when :operator
- token.build(@nodes.pop, tree).tap do |node|
- @nodes.push(node)
- end
- when :value
- token.build.tap do |leaf|
- @nodes.push(leaf)
- end
- end
- end
- rescue StopIteration
- @nodes.last || Lexeme::Null.new
- end
-
- def rpn_parse_tree
results = []
tokens_rpn.each do |token|
@@ -70,6 +37,12 @@ module Gitlab
results.pop
end
+ def self.seed(statement)
+ new(Expression::Lexer.new(statement).tokens)
+ end
+
+ private
+
# Parse the expression into Reverse Polish Notation
# (See: Shunting-yard algorithm)
def tokens_rpn
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 469a7fd9f7b..32d5e4b9ea3 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -45,7 +45,7 @@ module Gitlab
# need to be added to the application settings. To prevent Rake tasks
# and other callers from failing, use any loaded settings and return
# defaults for missing columns.
- if ActiveRecord::Migrator.needs_migration?
+ if ActiveRecord::Base.connection.migration_context.needs_migration?
db_attributes = current_settings&.attributes || {}
fake_application_settings(db_attributes)
elsif current_settings.present?
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index 1177f8ea99e..3e4c720b49a 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -128,7 +128,7 @@ module Gitlab
order = "#{field} IS NULL, #{order}" if direction == 'ASC'
end
- order
+ Arel.sql(order)
end
def self.nulls_first_order(field, direction = 'ASC')
@@ -142,7 +142,7 @@ module Gitlab
order = "#{field} IS NULL, #{order}" if direction == 'DESC'
end
- order
+ Arel.sql(order)
end
def self.random
@@ -284,17 +284,28 @@ module Gitlab
end
# inside_transaction? will return true if the caller is running within a transaction. Handles special cases
- # when running inside a test environment, in which the entire test is running with a DatabaseCleaner transaction
+ # when running inside a test environment, where tests may be wrapped in transactions
def self.inside_transaction?
- ActiveRecord::Base.connection.open_transactions > open_transactions_baseline
+ if Rails.env.test?
+ ActiveRecord::Base.connection.open_transactions > open_transactions_baseline
+ else
+ ActiveRecord::Base.connection.open_transactions > 0
+ end
end
- def self.open_transactions_baseline
- if ::Rails.env.test?
- return DatabaseCleaner.connections.count { |conn| conn.strategy.is_a?(DatabaseCleaner::ActiveRecord::Transaction) }
- end
+ # These methods that access @open_transactions_baseline are not thread-safe.
+ # These are fine though because we only call these in RSpec's main thread. If we decide to run
+ # specs multi-threaded, we would need to use something like ThreadGroup to keep track of this value
+ def self.set_open_transactions_baseline
+ @open_transactions_baseline = ActiveRecord::Base.connection.open_transactions
+ end
+
+ def self.reset_open_transactions_baseline
+ @open_transactions_baseline = 0
+ end
- 0
+ def self.open_transactions_baseline
+ @open_transactions_baseline ||= 0
end
private_class_method :open_transactions_baseline
diff --git a/lib/gitlab/database/grant.rb b/lib/gitlab/database/grant.rb
index 862ab96c887..26adf4e221b 100644
--- a/lib/gitlab/database/grant.rb
+++ b/lib/gitlab/database/grant.rb
@@ -24,7 +24,7 @@ module Gitlab
begin
from(nil)
- .pluck("has_table_privilege(#{quoted_table}, 'TRIGGER')")
+ .pluck(Arel.sql("has_table_privilege(#{quoted_table}, 'TRIGGER')"))
.first
rescue ActiveRecord::StatementInvalid
# This error is raised when using a non-existing table name. In this
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 091351e5cb2..0b6321c66ab 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -211,8 +211,7 @@ module Gitlab
metadata['call_site'] = feature.to_s if feature
metadata['gitaly-servers'] = address_metadata(remote_storage) if remote_storage
metadata['x-gitlab-correlation-id'] = Labkit::Correlation::CorrelationId.current_id if Labkit::Correlation::CorrelationId.current_id
- metadata['gitaly-session-id'] = session_id if Feature::Gitaly.enabled?(Feature::Gitaly::CATFILE_CACHE)
-
+ metadata['gitaly-session-id'] = session_id
metadata.merge!(Feature::Gitaly.server_feature_flags)
result = { metadata: metadata }
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index d8e9dccb644..ca3e5b51ecc 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -5,7 +5,7 @@ module Gitlab
class RepositoryService
include Gitlab::EncodingHelper
- MAX_MSG_SIZE = 128.kilobytes.freeze
+ MAX_MSG_SIZE = 128.kilobytes
def initialize(repository)
@repository = repository
diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb
index c28a1674018..b2fe9592c06 100644
--- a/lib/gitlab/import_export/attribute_cleaner.rb
+++ b/lib/gitlab/import_export/attribute_cleaner.rb
@@ -3,7 +3,7 @@
module Gitlab
module ImportExport
class AttributeCleaner
- ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + ['group_id']
+ ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + %w[group_id commit_id]
PROHIBITED_REFERENCES = Regexp.union(/\Acached_markdown_version\Z/, /_id\Z/, /_html\Z/).freeze
def self.clean(*args)
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index efd3f550a22..1b545b1d049 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -28,7 +28,7 @@ module Gitlab
links: 'Releases::Link',
metrics_setting: 'ProjectMetricsSetting' }.freeze
- USER_REFERENCES = %w[author_id assignee_id updated_by_id merged_by_id latest_closed_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id closed_by_id].freeze
+ USER_REFERENCES = %w[author_id assignee_id updated_by_id merged_by_id latest_closed_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id closed_by_id owner_id].freeze
PROJECT_REFERENCES = %w[project_id source_project_id target_project_id].freeze
@@ -78,6 +78,9 @@ module Gitlab
def create
return if unknown_service?
+ # Do not import legacy triggers
+ return if !Feature.enabled?(:use_legacy_pipeline_triggers, @project) && legacy_trigger?
+
setup_models
generate_imported_object
@@ -278,6 +281,10 @@ module Gitlab
!Object.const_defined?(parsed_relation_hash['type'])
end
+ def legacy_trigger?
+ @relation_name == 'Ci::Trigger' && @relation_hash['owner_id'].nil?
+ end
+
def find_or_create_object!
return relation_class.find_or_create_by(project_id: @project.id) if @relation_name == :project_feature
diff --git a/lib/gitlab/kubernetes/helm/client_command.rb b/lib/gitlab/kubernetes/helm/client_command.rb
index 9940272a8bf..6ae68306a9b 100644
--- a/lib/gitlab/kubernetes/helm/client_command.rb
+++ b/lib/gitlab/kubernetes/helm/client_command.rb
@@ -13,15 +13,27 @@ module Gitlab
end
def wait_for_tiller_command
+ helm_check = ['helm', 'version', *optional_tls_flags].shelljoin
# This is necessary to give Tiller time to restart after upgrade.
# Ideally we'd be able to use --wait but cannot because of
# https://github.com/helm/helm/issues/4855
- 'for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done'
+ "for i in $(seq 1 30); do #{helm_check} && break; sleep 1s; echo \"Retrying ($i)...\"; done"
end
def repository_command
['helm', 'repo', 'add', name, repository].shelljoin if repository
end
+
+ def optional_tls_flags
+ return [] unless files.key?(:'ca.pem')
+
+ [
+ '--tls',
+ '--tls-ca-cert', "#{files_dir}/ca.pem",
+ '--tls-cert', "#{files_dir}/cert.pem",
+ '--tls-key', "#{files_dir}/key.pem"
+ ]
+ end
end
end
end
diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb
index e33ba9305ce..9744a5f3d8a 100644
--- a/lib/gitlab/kubernetes/helm/install_command.rb
+++ b/lib/gitlab/kubernetes/helm/install_command.rb
@@ -95,17 +95,6 @@ module Gitlab
['--version', version]
end
-
- def optional_tls_flags
- return [] unless files.key?(:'ca.pem')
-
- [
- '--tls',
- '--tls-ca-cert', "#{files_dir}/ca.pem",
- '--tls-cert', "#{files_dir}/cert.pem",
- '--tls-key', "#{files_dir}/key.pem"
- ]
- end
end
end
end
diff --git a/lib/gitlab/lets_encrypt.rb b/lib/gitlab/lets_encrypt.rb
index cdf24f24647..08ad2ab91b0 100644
--- a/lib/gitlab/lets_encrypt.rb
+++ b/lib/gitlab/lets_encrypt.rb
@@ -2,15 +2,8 @@
module Gitlab
module LetsEncrypt
- def self.enabled?(pages_domain = nil)
- return false unless Gitlab::CurrentSettings.lets_encrypt_terms_of_service_accepted
-
- return false unless Feature.enabled?(:pages_auto_ssl)
-
- # If no domain is passed, just check whether we're enabled globally
- return true unless pages_domain
-
- !!pages_domain.project && Feature.enabled?(:pages_auto_ssl_for_project, pages_domain.project)
+ def self.enabled?
+ Gitlab::CurrentSettings.lets_encrypt_terms_of_service_accepted
end
end
end
diff --git a/lib/gitlab/omniauth_initializer.rb b/lib/gitlab/omniauth_initializer.rb
index 2a2083ebae0..ad1377a0892 100644
--- a/lib/gitlab/omniauth_initializer.rb
+++ b/lib/gitlab/omniauth_initializer.rb
@@ -52,6 +52,16 @@ module Gitlab
args[:strategy_class] = args[:strategy_class].constantize
end
+ # Providers that are known to depend on rack-oauth2, like those using
+ # Omniauth::Strategies::OpenIDConnect, need to be quirked so the
+ # client_auth_method argument value is passed as a symbol.
+ if (args[:strategy_class] == OmniAuth::Strategies::OpenIDConnect ||
+ args[:name] == 'openid_connect') &&
+ args[:client_auth_method].is_a?(String)
+
+ args[:client_auth_method] = args[:client_auth_method].to_sym
+ end
+
args
end
diff --git a/lib/gitlab/patch/active_record_query_cache.rb b/lib/gitlab/patch/active_record_query_cache.rb
new file mode 100644
index 00000000000..71d66bdbe02
--- /dev/null
+++ b/lib/gitlab/patch/active_record_query_cache.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+# Fixes a bug where the query cache isn't aware of the shared
+# ActiveRecord connection used in tests
+# https://github.com/rails/rails/issues/36587
+
+# To be removed with https://gitlab.com/gitlab-org/gitlab-ce/issues/64413
+
+module Gitlab
+ module Patch
+ module ActiveRecordQueryCache
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ def enable_query_cache!
+ @query_cache_enabled[connection_cache_key(current_thread)] = true
+ connection.enable_query_cache! if active_connection?
+ end
+
+ def disable_query_cache!
+ @query_cache_enabled.delete connection_cache_key(current_thread)
+ connection.disable_query_cache! if active_connection?
+ end
+
+ def query_cache_enabled
+ @query_cache_enabled[connection_cache_key(current_thread)]
+ end
+
+ def active_connection?
+ @thread_cached_conns[connection_cache_key(current_thread)]
+ end
+
+ private
+
+ def current_thread
+ @lock_thread || Thread.current
+ end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
+ end
+ end
+end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 7a1a2eaf6c0..e43147a3f37 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -4,14 +4,6 @@ module Gitlab
module Regex
extend self
- def namespace_name_regex
- @namespace_name_regex ||= /\A[\p{Alnum}\p{Pd}_\. ]*\z/.freeze
- end
-
- def namespace_name_regex_message
- "can contain only letters, digits, '_', '.', dash and space."
- end
-
def project_name_regex
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9c0}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9c0}_\. ]*\z/.freeze
end
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
index 9a8df719827..f6b2e2acf16 100644
--- a/lib/gitlab/url_blocker.rb
+++ b/lib/gitlab/url_blocker.rb
@@ -18,7 +18,6 @@ module Gitlab
# enforce_sanitization - Raises error if URL includes any HTML/CSS/JS tags and argument is true.
#
# Returns an array with [<uri>, <original-hostname>].
- # rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/ParameterLists
def validate!(
url,
@@ -30,7 +29,6 @@ module Gitlab
enforce_user: false,
enforce_sanitization: false,
dns_rebind_protection: true)
- # rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/ParameterLists
return [nil, nil] if url.nil?
@@ -38,36 +36,31 @@ module Gitlab
# Param url can be a string, URI or Addressable::URI
uri = parse_url(url)
- validate_html_tags!(uri) if enforce_sanitization
+ validate_uri(
+ uri: uri,
+ schemes: schemes,
+ ports: ports,
+ enforce_sanitization: enforce_sanitization,
+ enforce_user: enforce_user,
+ ascii_only: ascii_only
+ )
hostname = uri.hostname
port = get_port(uri)
- unless internal?(uri)
- validate_scheme!(uri.scheme, schemes)
- validate_port!(port, ports) if ports.any?
- validate_user!(uri.user) if enforce_user
- validate_hostname!(hostname)
- validate_unicode_restriction!(uri) if ascii_only
- end
-
- begin
- addrs_info = Addrinfo.getaddrinfo(hostname, port, nil, :STREAM).map do |addr|
- addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr
- end
- rescue SocketError
- return [uri, nil]
- end
+ address_info = get_address_info(hostname, port)
+ return [uri, nil] unless address_info
- protected_uri_with_hostname = enforce_uri_hostname(addrs_info, uri, hostname, dns_rebind_protection)
+ protected_uri_with_hostname = enforce_uri_hostname(address_info, uri, hostname, dns_rebind_protection)
# Allow url from the GitLab instance itself but only for the configured hostname and ports
return protected_uri_with_hostname if internal?(uri)
- validate_localhost!(addrs_info) unless allow_localhost
- validate_loopback!(addrs_info) unless allow_localhost
- validate_local_network!(addrs_info) unless allow_local_network
- validate_link_local!(addrs_info) unless allow_local_network
+ validate_local_request(
+ address_info: address_info,
+ allow_localhost: allow_localhost,
+ allow_local_network: allow_local_network
+ )
protected_uri_with_hostname
end
@@ -101,11 +94,44 @@ module Gitlab
[uri, hostname]
end
+ def validate_uri(uri:, schemes:, ports:, enforce_sanitization:, enforce_user:, ascii_only:)
+ validate_html_tags(uri) if enforce_sanitization
+
+ return if internal?(uri)
+
+ validate_scheme(uri.scheme, schemes)
+ validate_port(get_port(uri), ports) if ports.any?
+ validate_user(uri.user) if enforce_user
+ validate_hostname(uri.hostname)
+ validate_unicode_restriction(uri) if ascii_only
+ end
+
+ def get_address_info(hostname, port)
+ Addrinfo.getaddrinfo(hostname, port, nil, :STREAM).map do |addr|
+ addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr
+ end
+ rescue SocketError
+ end
+
+ def validate_local_request(address_info:, allow_localhost:, allow_local_network:)
+ return if allow_local_network && allow_localhost
+
+ unless allow_localhost
+ validate_localhost(address_info)
+ validate_loopback(address_info)
+ end
+
+ unless allow_local_network
+ validate_local_network(address_info)
+ validate_link_local(address_info)
+ end
+ end
+
def get_port(uri)
uri.port || uri.default_port
end
- def validate_html_tags!(uri)
+ def validate_html_tags(uri)
uri_str = uri.to_s
sanitized_uri = ActionController::Base.helpers.sanitize(uri_str, tags: [])
if sanitized_uri != uri_str
@@ -125,7 +151,7 @@ module Gitlab
CGI.unescape(url.to_s) =~ /\n|\r/
end
- def validate_port!(port, ports)
+ def validate_port(port, ports)
return if port.blank?
# Only ports under 1024 are restricted
return if port >= 1024
@@ -134,20 +160,20 @@ module Gitlab
raise BlockedUrlError, "Only allowed ports are #{ports.join(', ')}, and any over 1024"
end
- def validate_scheme!(scheme, schemes)
+ def validate_scheme(scheme, schemes)
if scheme.blank? || (schemes.any? && !schemes.include?(scheme))
raise BlockedUrlError, "Only allowed schemes are #{schemes.join(', ')}"
end
end
- def validate_user!(value)
+ def validate_user(value)
return if value.blank?
return if value =~ /\A\p{Alnum}/
raise BlockedUrlError, "Username needs to start with an alphanumeric character"
end
- def validate_hostname!(value)
+ def validate_hostname(value)
return if value.blank?
return if IPAddress.valid?(value)
return if value =~ /\A\p{Alnum}/
@@ -155,13 +181,13 @@ module Gitlab
raise BlockedUrlError, "Hostname or IP address invalid"
end
- def validate_unicode_restriction!(uri)
+ def validate_unicode_restriction(uri)
return if uri.to_s.ascii_only?
raise BlockedUrlError, "URI must be ascii only #{uri.to_s.dump}"
end
- def validate_localhost!(addrs_info)
+ def validate_localhost(addrs_info)
local_ips = ["::", "0.0.0.0"]
local_ips.concat(Socket.ip_address_list.map(&:ip_address))
@@ -170,19 +196,19 @@ module Gitlab
raise BlockedUrlError, "Requests to localhost are not allowed"
end
- def validate_loopback!(addrs_info)
+ def validate_loopback(addrs_info)
return unless addrs_info.any? { |addr| addr.ipv4_loopback? || addr.ipv6_loopback? }
raise BlockedUrlError, "Requests to loopback addresses are not allowed"
end
- def validate_local_network!(addrs_info)
+ def validate_local_network(addrs_info)
return unless addrs_info.any? { |addr| addr.ipv4_private? || addr.ipv6_sitelocal? || addr.ipv6_unique_local? }
raise BlockedUrlError, "Requests to the local network are not allowed"
end
- def validate_link_local!(addrs_info)
+ def validate_link_local(addrs_info)
netmask = IPAddr.new('169.254.0.0/16')
return unless addrs_info.any? { |addr| addr.ipv6_linklocal? || netmask.include?(addr.ip_address) }
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 0180fe7fa71..055e01a9399 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -130,7 +130,7 @@ module Gitlab
def usage_counters
{
- web_ide_commits: Gitlab::WebIdeCommitsCounter.total_count
+ web_ide_commits: Gitlab::UsageDataCounters::WebIdeCommitsCounter.total_count
}
end
diff --git a/lib/gitlab/usage_data_counters/redis_counter.rb b/lib/gitlab/usage_data_counters/redis_counter.rb
new file mode 100644
index 00000000000..123b8e1bef1
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/redis_counter.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module UsageDataCounters
+ module RedisCounter
+ def increment
+ Gitlab::Redis::SharedState.with { |redis| redis.incr(redis_counter_key) }
+ end
+
+ def total_count
+ Gitlab::Redis::SharedState.with { |redis| redis.get(redis_counter_key).to_i }
+ end
+
+ def redis_counter_key
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data_counters/web_ide_commits_counter.rb b/lib/gitlab/usage_data_counters/web_ide_commits_counter.rb
new file mode 100644
index 00000000000..62236fa07a3
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/web_ide_commits_counter.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module UsageDataCounters
+ class WebIdeCommitsCounter
+ extend RedisCounter
+
+ def self.redis_counter_key
+ 'WEB_IDE_COMMITS_COUNT'
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/web_ide_commits_counter.rb b/lib/gitlab/web_ide_commits_counter.rb
deleted file mode 100644
index 1cd9b5295b9..00000000000
--- a/lib/gitlab/web_ide_commits_counter.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module WebIdeCommitsCounter
- WEB_IDE_COMMITS_KEY = "WEB_IDE_COMMITS_COUNT".freeze
-
- class << self
- def increment
- Gitlab::Redis::SharedState.with { |redis| redis.incr(WEB_IDE_COMMITS_KEY) }
- end
-
- def total_count
- Gitlab::Redis::SharedState.with { |redis| redis.get(WEB_IDE_COMMITS_KEY).to_i }
- end
- end
- end
-end
diff --git a/lib/tasks/gitlab/features.rake b/lib/tasks/gitlab/features.rake
index d88bcca0819..9cf568c07fe 100644
--- a/lib/tasks/gitlab/features.rake
+++ b/lib/tasks/gitlab/features.rake
@@ -10,14 +10,22 @@ namespace :gitlab do
set_rugged_feature_flags(false)
puts 'All Rugged feature flags were disabled.'
end
+
+ task unset_rugged: :environment do
+ set_rugged_feature_flags(nil)
+ puts 'All Rugged feature flags were unset.'
+ end
end
def set_rugged_feature_flags(status)
Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS.each do |flag|
- if status
- Feature.enable(flag)
- else
+ case status
+ when nil
Feature.get(flag).remove
+ when true
+ Feature.enable(flag)
+ when false
+ Feature.disable(flag)
end
end
end
diff --git a/lib/tasks/gitlab/seed.rake b/lib/tasks/gitlab/seed.rake
index 155ba979b36..d76e38b73b5 100644
--- a/lib/tasks/gitlab/seed.rake
+++ b/lib/tasks/gitlab/seed.rake
@@ -1,7 +1,9 @@
namespace :gitlab do
namespace :seed do
desc "GitLab | Seed | Seeds issues"
- task :issues, [:project_full_path] => :environment do |t, args|
+ task :issues, [:project_full_path, :backfill_weeks, :average_issues_per_week] => :environment do |t, args|
+ args.with_defaults(backfill_weeks: 5, average_issues_per_week: 2)
+
projects =
if args.project_full_path
project = Project.find_by_full_path(args.project_full_path)
@@ -26,7 +28,8 @@ namespace :gitlab do
projects.each do |project|
puts "\nSeeding issues for the '#{project.full_path}' project"
seeder = Quality::Seeders::Issues.new(project: project)
- issues_created = seeder.seed(backfill_weeks: 5, average_issues_per_week: 2)
+ issues_created = seeder.seed(backfill_weeks: args.backfill_weeks.to_i,
+ average_issues_per_week: args.average_issues_per_week.to_i)
puts "\n#{issues_created} issues created!"
end
end
diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po
index 7ccdfa282e8..8e8a678fb49 100644
--- a/locale/ar_SA/gitlab.po
+++ b/locale/ar_SA/gitlab.po
@@ -16935,7 +16935,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 9e24b950cdd..6ac32a51c4a 100644
--- a/locale/bg/gitlab.po
+++ b/locale/bg/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/bn_BD/gitlab.po b/locale/bn_BD/gitlab.po
index c7c0695b580..ed6daeb61cf 100644
--- a/locale/bn_BD/gitlab.po
+++ b/locale/bn_BD/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/bn_IN/gitlab.po b/locale/bn_IN/gitlab.po
index 56c5a3b3704..82a88455eb6 100644
--- a/locale/bn_IN/gitlab.po
+++ b/locale/bn_IN/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po
index c0b4aea4a99..7f85efb992b 100644
--- a/locale/ca_ES/gitlab.po
+++ b/locale/ca_ES/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po
index 1184a326ede..3e51d44aea9 100644
--- a/locale/cs_CZ/gitlab.po
+++ b/locale/cs_CZ/gitlab.po
@@ -16777,7 +16777,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/cy_GB/gitlab.po b/locale/cy_GB/gitlab.po
index 019dcd25e72..ac295b22014 100644
--- a/locale/cy_GB/gitlab.po
+++ b/locale/cy_GB/gitlab.po
@@ -16935,7 +16935,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po
index f30fbc0806c..697d555d4f5 100644
--- a/locale/da_DK/gitlab.po
+++ b/locale/da_DK/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index 7faeed34e59..d8355c1a73b 100644
--- a/locale/de/gitlab.po
+++ b/locale/de/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr "nicht verfügbar"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/el_GR/gitlab.po b/locale/el_GR/gitlab.po
index 2ac09933c10..02262e56399 100644
--- a/locale/el_GR/gitlab.po
+++ b/locale/el_GR/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index df88e81f3d3..efac588a37b 100644
--- a/locale/eo/gitlab.po
+++ b/locale/eo/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index 616ef854a7d..d29d12c7f19 100644
--- a/locale/es/gitlab.po
+++ b/locale/es/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr "debe ser mayor que la fecha de inicio"
msgid "n/a"
msgstr "n/a"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr "el intervalo debe estar comprendido entre 10 minutos y 1 mes"
msgid "new merge request"
diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po
index c7473191a42..e8cdb077a90 100644
--- a/locale/et_EE/gitlab.po
+++ b/locale/et_EE/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
index be757241241..0ed26efcd80 100644
--- a/locale/fil_PH/gitlab.po
+++ b/locale/fil_PH/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index 9b938ee38e6..e0945260d76 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr "non disponible"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a4fee96753d..5e8d1ac206a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -138,9 +138,15 @@ msgstr[1] ""
msgid "%{edit_in_new_fork_notice} Try to cherry-pick this commit again."
msgstr ""
+msgid "%{edit_in_new_fork_notice} Try to create a new directory again."
+msgstr ""
+
msgid "%{edit_in_new_fork_notice} Try to revert this commit again."
msgstr ""
+msgid "%{edit_in_new_fork_notice} Try to upload a file again."
+msgstr ""
+
msgid "%{filePath} deleted"
msgstr ""
@@ -171,9 +177,6 @@ msgstr ""
msgid "%{level_name} is not allowed since the fork source project has lower visibility."
msgstr ""
-msgid "%{level_name} visibility has been restricted by the administrator."
-msgstr ""
-
msgid "%{link_start}Read more%{link_end} about role permissions"
msgstr ""
@@ -707,6 +710,9 @@ msgstr ""
msgid "Add to review"
msgstr ""
+msgid "Add to tree"
+msgstr ""
+
msgid "Add user(s) to the group:"
msgstr ""
@@ -2981,6 +2987,12 @@ msgstr ""
msgid "ContainerRegistry|Container Registry"
msgstr ""
+msgid "ContainerRegistry|Copy build command to clipboard"
+msgstr ""
+
+msgid "ContainerRegistry|Copy push command to clipboard"
+msgstr ""
+
msgid "ContainerRegistry|Docker connection error"
msgstr ""
@@ -3014,13 +3026,13 @@ msgstr ""
msgid "ContainerRegistry|There are no container images stored for this project"
msgstr ""
-msgid "ContainerRegistry|We are having trouble connecting to Docker, which could be due to an issue with your project name or path. For more information, please review the %{docLinkStart}Container Registry documentation%{docLinkEnd}."
+msgid "ContainerRegistry|We are having trouble connecting to Docker, which could be due to an issue with your project name or path. %{docLinkStart}More Information%{docLinkEnd}"
msgstr ""
-msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. Learn more about the %{docLinkStart}Container Registry%{docLinkEnd}."
+msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
msgstr ""
-msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images. Learn more about the %{docLinkStart}Container Registry%{docLinkEnd}."
+msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
msgstr ""
msgid "ContainerRegistry|You are about to delete the image <b>%{title}</b>. This will delete the image and all tags pointing to this image."
@@ -7228,6 +7240,9 @@ msgstr ""
msgid "Other Labels"
msgstr ""
+msgid "Other visibility settings have been disabled by the administrator."
+msgstr ""
+
msgid "Outbound requests"
msgstr ""
@@ -9727,6 +9742,9 @@ msgstr ""
msgid "Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead."
msgstr ""
+msgid "Someone edited the issue at the same time you did. Please check out %{linkStart}the issue%{linkEnd} and make sure your changes will not unintentionally remove theirs."
+msgstr ""
+
msgid "Someone edited this %{issueType} at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
@@ -11974,6 +11992,9 @@ msgstr ""
msgid "Visibility level:"
msgstr ""
+msgid "Visibility settings have been disabled by the administrator."
+msgstr ""
+
msgid "Visibility, project features, permissions"
msgstr ""
@@ -12507,6 +12528,9 @@ msgstr ""
msgid "You'll need to use different branch names to get a valid comparison."
msgstr ""
+msgid "You're not allowed to %{tag_start}edit%{tag_end} files in this project directly. Please fork this project, make your changes there, and submit a merge request."
+msgstr ""
+
msgid "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
msgstr ""
@@ -13096,7 +13120,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po
index 50d4d42f36a..cfa68fccd1e 100644
--- a/locale/gl_ES/gitlab.po
+++ b/locale/gl_ES/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po
index dc6ff543726..7e76e201e2b 100644
--- a/locale/he_IL/gitlab.po
+++ b/locale/he_IL/gitlab.po
@@ -16777,7 +16777,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/hi_IN/gitlab.po b/locale/hi_IN/gitlab.po
index 126759c5828..c7f261878b2 100644
--- a/locale/hi_IN/gitlab.po
+++ b/locale/hi_IN/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/hr_HR/gitlab.po b/locale/hr_HR/gitlab.po
index 1f3242a6731..cac5c0a35cd 100644
--- a/locale/hr_HR/gitlab.po
+++ b/locale/hr_HR/gitlab.po
@@ -16698,7 +16698,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/hu_HU/gitlab.po b/locale/hu_HU/gitlab.po
index 142845c24a7..4ae0ab94c31 100644
--- a/locale/hu_HU/gitlab.po
+++ b/locale/hu_HU/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
index be6c29d933c..12578ba567c 100644
--- a/locale/id_ID/gitlab.po
+++ b/locale/id_ID/gitlab.po
@@ -16540,7 +16540,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 9b3ec180972..26d2a6c9be7 100644
--- a/locale/it/gitlab.po
+++ b/locale/it/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index cc27cb06364..8a05c69ca85 100644
--- a/locale/ja/gitlab.po
+++ b/locale/ja/gitlab.po
@@ -16540,7 +16540,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/ka_GE/gitlab.po b/locale/ka_GE/gitlab.po
index f6d768828ca..202f4a1ce28 100644
--- a/locale/ka_GE/gitlab.po
+++ b/locale/ka_GE/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index 6138874ac7d..955221059f3 100644
--- a/locale/ko/gitlab.po
+++ b/locale/ko/gitlab.po
@@ -16540,7 +16540,7 @@ msgstr ""
msgid "n/a"
msgstr "해당 없음"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po
index 11bb2a40d14..12cad4d8ba7 100644
--- a/locale/mn_MN/gitlab.po
+++ b/locale/mn_MN/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po
index 7f150c167ee..8cac58c66bd 100644
--- a/locale/nb_NO/gitlab.po
+++ b/locale/nb_NO/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index faa40d15de9..24f3c7d8527 100644
--- a/locale/nl_NL/gitlab.po
+++ b/locale/nl_NL/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/pa_IN/gitlab.po b/locale/pa_IN/gitlab.po
index 723f2d4cb22..7120181643f 100644
--- a/locale/pa_IN/gitlab.po
+++ b/locale/pa_IN/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index e3b257d8c16..a8ab402925b 100644
--- a/locale/pl_PL/gitlab.po
+++ b/locale/pl_PL/gitlab.po
@@ -16777,7 +16777,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 0a1e2508d66..750b4987ed3 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr "n/a"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/pt_PT/gitlab.po b/locale/pt_PT/gitlab.po
index f9174152adf..57cb6132b5f 100644
--- a/locale/pt_PT/gitlab.po
+++ b/locale/pt_PT/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po
index 71e8f9b199d..f3f04dd449b 100644
--- a/locale/ro_RO/gitlab.po
+++ b/locale/ro_RO/gitlab.po
@@ -16698,7 +16698,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index bb9e59a36a4..2ca9e319998 100644
--- a/locale/ru/gitlab.po
+++ b/locale/ru/gitlab.po
@@ -16777,7 +16777,7 @@ msgstr ""
msgid "n/a"
msgstr "н/д"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/sk_SK/gitlab.po b/locale/sk_SK/gitlab.po
index 0b014f91082..68e64991e06 100644
--- a/locale/sk_SK/gitlab.po
+++ b/locale/sk_SK/gitlab.po
@@ -16777,7 +16777,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po
index 2e43589b1fc..436c7e6034f 100644
--- a/locale/sq_AL/gitlab.po
+++ b/locale/sq_AL/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/sr_CS/gitlab.po b/locale/sr_CS/gitlab.po
index 34ba686fc45..02ac3e67563 100644
--- a/locale/sr_CS/gitlab.po
+++ b/locale/sr_CS/gitlab.po
@@ -16698,7 +16698,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/sr_SP/gitlab.po b/locale/sr_SP/gitlab.po
index cefbe0910c4..9b22d51e687 100644
--- a/locale/sr_SP/gitlab.po
+++ b/locale/sr_SP/gitlab.po
@@ -16698,7 +16698,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/sv_SE/gitlab.po b/locale/sv_SE/gitlab.po
index 33c75c49a0f..b39f28cda0e 100644
--- a/locale/sv_SE/gitlab.po
+++ b/locale/sv_SE/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/sw_KE/gitlab.po b/locale/sw_KE/gitlab.po
index 63860064d3c..bc2a228362c 100644
--- a/locale/sw_KE/gitlab.po
+++ b/locale/sw_KE/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
index 3b552a3cbda..b801b5a93f4 100644
--- a/locale/tr_TR/gitlab.po
+++ b/locale/tr_TR/gitlab.po
@@ -16619,7 +16619,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr "10 dakika ile 1 ay arasında olması gerekiyor"
msgid "new merge request"
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index ee9d9bc0fee..b9056ca8ae1 100644
--- a/locale/uk/gitlab.po
+++ b/locale/uk/gitlab.po
@@ -16777,7 +16777,7 @@ msgstr "повинна бути пізніша за дату початку"
msgid "n/a"
msgstr "н/д"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr "має бути між 10 хвилинами та 1 місяцем"
msgid "new merge request"
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index bfa6064303c..ba86aa74c64 100644
--- a/locale/zh_CN/gitlab.po
+++ b/locale/zh_CN/gitlab.po
@@ -16540,7 +16540,7 @@ msgstr "必须大于开始日期"
msgid "n/a"
msgstr "不适用"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr "需要在10分钟到1个月之间"
msgid "new merge request"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 541978fd726..d5ead45d34f 100644
--- a/locale/zh_HK/gitlab.po
+++ b/locale/zh_HK/gitlab.po
@@ -16540,7 +16540,7 @@ msgstr ""
msgid "n/a"
msgstr ""
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index 22de348bdaa..308c1cfd9fd 100644
--- a/locale/zh_TW/gitlab.po
+++ b/locale/zh_TW/gitlab.po
@@ -16540,7 +16540,7 @@ msgstr ""
msgid "n/a"
msgstr "未知"
-msgid "needs to be beetween 10 minutes and 1 month"
+msgid "needs to be between 10 minutes and 1 month"
msgstr ""
msgid "new merge request"
diff --git a/package.json b/package.json
index 5955790488a..44aa850860e 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"@babel/preset-env": "^7.4.4",
"@gitlab/csslab": "^1.9.0",
"@gitlab/svgs": "^1.67.0",
- "@gitlab/ui": "^5.5.0",
+ "@gitlab/ui": "^5.6.0",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 130e5e33ab4..80ce23d5c38 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -26,7 +26,7 @@ module QA
end
def retry_until(max_attempts: 3, reload: false, sleep_interval: 0)
- QA::Support::Retrier.retry_until(max_attempts: max_attempts, reload: reload, sleep_interval: sleep_interval) do
+ QA::Support::Retrier.retry_until(max_attempts: max_attempts, reload_page: (reload && self), sleep_interval: sleep_interval) do
yield
end
end
diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb
index 7a01320901d..9e6fd2fdd4f 100644
--- a/qa/qa/page/element.rb
+++ b/qa/qa/page/element.rb
@@ -28,7 +28,7 @@ module QA
end
def selector_css
- ".#{selector}"
+ %Q([data-qa-selector="#{@name}"],.#{selector})
end
def expression
@@ -40,7 +40,7 @@ module QA
end
def matches?(line)
- !!(line =~ expression)
+ !!(line =~ /["']#{name}['"]|#{expression}/)
end
end
end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 9c99e43d4c0..c98d85d7911 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -12,7 +12,7 @@ module QA
view 'app/views/layouts/header/_default.html.haml' do
element :navbar, required: true
element :user_avatar, required: true
- element :user_menu, '.dropdown-menu' # rubocop:disable QA/ElementWithPattern
+ element :user_menu, required: true
end
view 'app/views/layouts/nav/_dashboard.html.haml' do
@@ -82,7 +82,7 @@ module QA
private
def within_top_menu
- page.within('.qa-navbar') do
+ within_element(:navbar) do
yield
end
end
@@ -91,7 +91,7 @@ module QA
within_top_menu do
click_element :user_avatar
- page.within('.dropdown-menu') do
+ within_element(:user_menu) do
yield
end
end
diff --git a/qa/qa/page/project/operations/kubernetes/show.rb b/qa/qa/page/project/operations/kubernetes/show.rb
index 4f625c5f0f0..eb30e0ea02a 100644
--- a/qa/qa/page/project/operations/kubernetes/show.rb
+++ b/qa/qa/page/project/operations/kubernetes/show.rb
@@ -28,16 +28,12 @@ module QA
end
end
- def await_installed(application_name, button_text: 'Installed')
+ def await_installed(application_name)
within(".js-cluster-application-row-#{application_name}") do
- page.has_text?(button_text, wait: 300)
+ page.has_text?(/Installed|Uninstall/, wait: 300)
end
end
- def await_uninstallable(application_name)
- await_installed(application_name, button_text: 'Uninstall')
- end
-
def ingress_ip
# We need to wait longer since it can take some time before the
# ip address is assigned for the ingress controller
diff --git a/qa/qa/resource/kubernetes_cluster.rb b/qa/qa/resource/kubernetes_cluster.rb
index 1dd93dd5b88..27ab7b60211 100644
--- a/qa/qa/resource/kubernetes_cluster.rb
+++ b/qa/qa/resource/kubernetes_cluster.rb
@@ -47,7 +47,7 @@ module QA
page.install!(:runner) if @install_runner
page.await_installed(:ingress) if @install_ingress
- page.await_uninstallable(:prometheus) if @install_prometheus
+ page.await_installed(:prometheus) if @install_prometheus
page.await_installed(:runner) if @install_runner
if @install_ingress
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
index 5cd6bac3f5a..09d1d3fe76e 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
@@ -11,7 +11,7 @@ module QA
expect(menu).to have_personal_area
end
- Support::Retrier.retry_until(reload: false, sleep_interval: 0.5) do
+ Support::Retrier.retry_until(sleep_interval: 0.5) do
Page::Main::Menu.perform(&:sign_out)
Page::Main::Login.perform(&:has_sign_in_tab?)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
index 2b3d9b1711d..36cbd1b81f0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
@@ -56,7 +56,7 @@ module QA
project.visit!
end
- it 'branches are correctly listed after CRUD operations' do
+ it 'lists branches correctly after CRUD operations' do
Page::Project::Menu.perform(&:go_to_repository_branches)
expect(page).to have_content(master_branch)
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb
index b060f15168c..b2c70547421 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb
@@ -7,12 +7,12 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- project = Resource::Project.fabricate! do |project|
+ project = Resource::Project.fabricate_via_api! do |project|
project.name = 'project-with-ci-variables'
project.description = 'project with CI variables'
end
- Resource::CiVariable.fabricate! do |resource|
+ Resource::CiVariable.fabricate_via_api! do |resource|
resource.project = project
resource.key = 'VARIABLE_KEY'
resource.value = 'some_CI_variable'
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
index aa01e5a618e..6f39a755392 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/26
- context 'Release', :quarantine do
+ context 'Release' do
describe 'Deploy key creation' do
it 'user adds a deploy key' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
index caa9be341b4..791dc62e32f 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
@@ -10,7 +10,7 @@ module QA
deploy_token_name = 'deploy token name'
one_week_from_now = Date.today + 7
- deploy_token = Resource::DeployToken.fabricate! do |resource|
+ deploy_token = Resource::DeployToken.fabricate_via_browser_ui! do |resource|
resource.name = deploy_token_name
resource.expires_at = one_week_from_now
end
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index 99f0838b864..60c1e105ae6 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -55,8 +55,7 @@ module QA
end
end
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/108
- describe 'Auto DevOps support', :orchestrated, :kubernetes, :quarantine do
+ describe 'Auto DevOps support', :orchestrated, :kubernetes do
context 'when rbac is enabled' do
before(:all) do
@cluster = Service::KubernetesCluster.new.create!
diff --git a/qa/qa/support/retrier.rb b/qa/qa/support/retrier.rb
index 230cec8f8d2..720f1d17037 100644
--- a/qa/qa/support/retrier.rb
+++ b/qa/qa/support/retrier.rb
@@ -24,8 +24,8 @@ module QA
end
end
- def retry_until(max_attempts: 3, reload: false, sleep_interval: 0)
- QA::Runtime::Logger.debug("with retry_until: max_attempts #{max_attempts}; sleep_interval #{sleep_interval}; reload:#{reload}")
+ def retry_until(max_attempts: 3, reload_page: nil, sleep_interval: 0)
+ QA::Runtime::Logger.debug("with retry_until: max_attempts #{max_attempts}; sleep_interval #{sleep_interval}; reload_page:#{reload_page}")
attempts = 0
while attempts < max_attempts
@@ -35,7 +35,7 @@ module QA
sleep sleep_interval
- refresh if reload
+ reload_page.refresh if reload_page
attempts += 1
end
diff --git a/qa/spec/page/element_spec.rb b/qa/spec/page/element_spec.rb
index f746fe06e40..20d4a00c020 100644
--- a/qa/spec/page/element_spec.rb
+++ b/qa/spec/page/element_spec.rb
@@ -11,7 +11,7 @@ describe QA::Page::Element do
describe '#selector_css' do
it 'transforms element name into QA-specific clickable css selector' do
expect(described_class.new(:sign_in_button).selector_css)
- .to eq '.qa-sign-in-button'
+ .to include('.qa-sign-in-button')
end
end
@@ -49,6 +49,10 @@ describe QA::Page::Element do
it 'does not match if QA selector is not there' do
expect(subject.matches?('some_name selector')).to be false
end
+
+ it 'matches when element name is specified' do
+ expect(subject.matches?('data:{qa:{selector:"some_name"}}')).to be true
+ end
end
describe 'attributes' do
@@ -106,4 +110,11 @@ describe QA::Page::Element do
end
end
end
+
+ describe 'data-qa selectors' do
+ subject { described_class.new(:my_element) }
+ it 'properly translates to a data-qa-selector' do
+ expect(subject.selector_css).to include(%q([data-qa-selector="my_element"]))
+ end
+ end
end
diff --git a/rubocop/cop/qa/element_with_pattern.rb b/rubocop/cop/qa/element_with_pattern.rb
index d14eeaaeaf3..d48f4725488 100644
--- a/rubocop/cop/qa/element_with_pattern.rb
+++ b/rubocop/cop/qa/element_with_pattern.rb
@@ -30,7 +30,7 @@ module RuboCop
return if args.first.nil?
args.first.each_node(:str) do |arg|
- add_offense(arg, message: MESSAGE % "qa-#{element_name.value.to_s.tr('_', '-')}")
+ add_offense(arg, message: MESSAGE % "data-qa-selector=#{element_name.value}")
end
end
diff --git a/scripts/gather-test-memory-data b/scripts/gather-test-memory-data
new file mode 100755
index 00000000000..9992a83e6a6
--- /dev/null
+++ b/scripts/gather-test-memory-data
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+
+require 'csv'
+
+def join_csv_files(output_path, input_paths)
+ return if input_paths.empty?
+
+ input_csvs = input_paths.map do |input_path|
+ CSV.read(input_path, headers: true)
+ end
+
+ CSV.open(output_path, "w", headers: input_csvs.first.headers, write_headers: true) do |output_csv|
+ input_csvs.each do |input_csv|
+ input_csv.each do |line|
+ output_csv << line
+ end
+ end
+ end
+end
+
+join_csv_files('tmp/memory_test/report.csv', Dir['tmp/memory_test/*.csv'].sort)
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index 2055ce7f09d..8c9b8b9fb02 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -45,7 +45,7 @@ then
then
echo
echo ' ✖ ERROR: New README.md file(s) detected, prefer index.md over README.md.' >&2
- echo ' https://docs.gitlab.com/ee/development/writing_documentation.html#location-and-naming-documents'
+ echo ' https://docs.gitlab.com/ee/development/documentation/styleguide.html#working-with-directories-and-files'
echo
exit 1
fi
@@ -55,7 +55,7 @@ then
then
echo
echo ' ✖ ERROR: New README.md file(s) detected, prefer index.md over README.md.' >&2
- echo ' https://docs.gitlab.com/ee/development/writing_documentation.html#location-and-naming-documents'
+ echo ' https://docs.gitlab.com/ee/development/documentation/styleguide.html#working-with-directories-and-files'
echo
exit 1
fi
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 2bf654b1e24..bc47884ee45 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -132,13 +132,14 @@ function install_external_dns() {
echoinfo "Installing external-dns Helm chart"
helm repo update
# Default requested: CPU => 0, memory => 0
- helm install stable/external-dns \
+ helm install stable/external-dns --version '^2.2.1' \
-n "${release_name}" \
--namespace "${KUBE_NAMESPACE}" \
--set provider="aws" \
- --set aws.secretKey="${REVIEW_APPS_AWS_SECRET_KEY}" \
- --set aws.accessKey="${REVIEW_APPS_AWS_ACCESS_KEY}" \
+ --set aws.credentials.secretKey="${REVIEW_APPS_AWS_SECRET_KEY}" \
+ --set aws.credentials.accessKey="${REVIEW_APPS_AWS_ACCESS_KEY}" \
--set aws.zoneType="public" \
+ --set aws.batchChangeSize=400 \
--set domainFilters[0]="${domain}" \
--set txtOwnerId="${KUBE_NAMESPACE}" \
--set rbac.create="true" \
diff --git a/scripts/trigger-build-docs b/scripts/trigger-build-docs
index 0fc8f6fbd4b..83841512f1c 100755
--- a/scripts/trigger-build-docs
+++ b/scripts/trigger-build-docs
@@ -13,7 +13,7 @@ end
#
# The remote docs project
#
-GITLAB_DOCS_REPO = 'gitlab-com/gitlab-docs'.freeze
+GITLAB_DOCS_REPO = 'gitlab-org/gitlab-docs'.freeze
#
# Truncate the remote docs branch name otherwise we hit the filesystem
@@ -31,7 +31,7 @@ end
# to avoid race conditions, since a triggered pipeline will also run right
# after the branch creation. This only happens the very first time a branch
# is created and will be skipped in subsequent runs. Read more in
-# https://gitlab.com/gitlab-com/gitlab-docs/issues/154.
+# https://gitlab.com/gitlab-org/gitlab-docs/issues/154.
#
def create_remote_branch
Gitlab.create_branch(GITLAB_DOCS_REPO, docs_branch, 'master')
@@ -81,7 +81,7 @@ def slug
end
#
-# Overriding vars in https://gitlab.com/gitlab-com/gitlab-docs/blob/master/.gitlab-ci.yml
+# Overriding vars in https://gitlab.com/gitlab-org/gitlab-docs/blob/master/.gitlab-ci.yml
#
def param_name
"BRANCH_#{slug.upcase}"
diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb
index 5ad5f9cdeea..4eb0545eb6c 100644
--- a/spec/controllers/admin/application_settings_controller_spec.rb
+++ b/spec/controllers/admin/application_settings_controller_spec.rb
@@ -41,7 +41,7 @@ describe Admin::ApplicationSettingsController do
it 'returns JSON data' do
get :usage_data, format: :json
- body = JSON.parse(response.body)
+ body = json_response
expect(body["version"]).to eq(Gitlab::VERSION)
expect(body).to include('counts')
expect(response.status).to eq(200)
diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb
index 78c5e2a2656..bbeda7dae0f 100644
--- a/spec/controllers/admin/runners_controller_spec.rb
+++ b/spec/controllers/admin/runners_controller_spec.rb
@@ -23,10 +23,11 @@ describe Admin::RunnersController do
control_count = ActiveRecord::QueryRecorder.new { get :index }.count
- create(:ci_runner, :tagged_only)
+ create_list(:ci_runner, 5, :tagged_only)
# There is still an N+1 query for `runner.builds.count`
- expect { get :index }.not_to exceed_query_limit(control_count + 1)
+ # We also need to add 1 because it takes 2 queries to preload tags
+ expect { get :index }.not_to exceed_query_limit(control_count + 6)
expect(response).to have_gitlab_http_status(200)
expect(response.body).to have_content('tag1')
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 447a12b2fac..84bbbac39b0 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -63,8 +63,6 @@ describe ApplicationController do
sign_in user
end
- let(:json_response) { JSON.parse(response.body) }
-
controller(described_class) do
def index
render json: Gon.all_variables
diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb
index 6cad060d888..0db58fbefc1 100644
--- a/spec/controllers/boards/issues_controller_spec.rb
+++ b/spec/controllers/boards/issues_controller_spec.rb
@@ -52,10 +52,8 @@ describe Boards::IssuesController do
list_issues user: user, board: board, list: list2
- parsed_response = JSON.parse(response.body)
-
expect(response).to match_response_schema('entities/issue_boards')
- expect(parsed_response['issues'].length).to eq 2
+ expect(json_response['issues'].length).to eq 2
expect(development.issues.map(&:relative_position)).not_to include(nil)
end
@@ -123,10 +121,8 @@ describe Boards::IssuesController do
list_issues user: user, board: board
- parsed_response = JSON.parse(response.body)
-
expect(response).to match_response_schema('entities/issue_boards')
- expect(parsed_response['issues'].length).to eq 2
+ expect(json_response['issues'].length).to eq 2
end
end
@@ -164,7 +160,7 @@ describe Boards::IssuesController do
end
end
- describe 'PUT move_multiple' do
+ describe 'PUT bulk_move' do
let(:todo) { create(:group_label, group: group, name: 'Todo') }
let(:development) { create(:group_label, group: group, name: 'Development') }
let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
@@ -200,6 +196,20 @@ describe Boards::IssuesController do
sign_in(signed_in_user)
end
+ it 'responds as expected' do
+ put :bulk_move, params: move_issues_params
+ expect(response).to have_gitlab_http_status(expected_status)
+
+ if expected_status == 200
+ expect(json_response).to include(
+ 'count' => move_issues_params[:ids].size,
+ 'success' => true
+ )
+
+ expect(json_response['issues'].pluck('id')).to match_array(move_issues_params[:ids])
+ end
+ end
+
it 'moves issues as expected' do
put :bulk_move, params: move_issues_params
expect(response).to have_gitlab_http_status(expected_status)
diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb
index e1f75fa3395..418ca6f3210 100644
--- a/spec/controllers/boards/lists_controller_spec.rb
+++ b/spec/controllers/boards/lists_controller_spec.rb
@@ -26,10 +26,8 @@ describe Boards::ListsController do
read_board_list user: user, board: board
- parsed_response = JSON.parse(response.body)
-
expect(response).to match_response_schema('lists')
- expect(parsed_response.length).to eq 3
+ expect(json_response.length).to eq 3
end
context 'with unauthorized user' do
diff --git a/spec/controllers/groups/boards_controller_spec.rb b/spec/controllers/groups/boards_controller_spec.rb
index 5e0f64ccca4..e4232c2c1ab 100644
--- a/spec/controllers/groups/boards_controller_spec.rb
+++ b/spec/controllers/groups/boards_controller_spec.rb
@@ -63,10 +63,8 @@ describe Groups::BoardsController do
list_boards format: :json
- parsed_response = JSON.parse(response.body)
-
expect(response).to match_response_schema('boards')
- expect(parsed_response.length).to eq 1
+ expect(json_response.length).to eq 1
end
context 'with unauthorized user' do
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
index 19b18091aef..bf164aeed38 100644
--- a/spec/controllers/groups/milestones_controller_spec.rb
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -73,7 +73,7 @@ describe Groups::MilestonesController do
it 'lists legacy group milestones and group milestones' do
get :index, params: { group_id: group.to_param }, format: :json
- milestones = JSON.parse(response.body)
+ milestones = json_response
expect(milestones.count).to eq(2)
expect(milestones.first["title"]).to eq("group milestone")
diff --git a/spec/controllers/health_check_controller_spec.rb b/spec/controllers/health_check_controller_spec.rb
index 19d739fcf4f..92f005faf4a 100644
--- a/spec/controllers/health_check_controller_spec.rb
+++ b/spec/controllers/health_check_controller_spec.rb
@@ -5,7 +5,6 @@ require 'spec_helper'
describe HealthCheckController do
include StubENV
- let(:json_response) { JSON.parse(response.body) }
let(:xml_response) { Hash.from_xml(response.body)['hash'] }
let(:token) { Gitlab::CurrentSettings.health_check_access_token }
let(:whitelisted_ip) { '127.0.0.1' }
diff --git a/spec/controllers/health_controller_spec.rb b/spec/controllers/health_controller_spec.rb
index fc62a8310aa..e82dcfcdb64 100644
--- a/spec/controllers/health_controller_spec.rb
+++ b/spec/controllers/health_controller_spec.rb
@@ -5,7 +5,6 @@ require 'spec_helper'
describe HealthController do
include StubENV
- let(:json_response) { JSON.parse(response.body) }
let(:token) { Gitlab::CurrentSettings.health_check_access_token }
let(:whitelisted_ip) { '127.0.0.1' }
let(:not_whitelisted_ip) { '127.0.0.2' }
diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb
index ee454a7818c..84027119491 100644
--- a/spec/controllers/metrics_controller_spec.rb
+++ b/spec/controllers/metrics_controller_spec.rb
@@ -5,7 +5,6 @@ require 'spec_helper'
describe MetricsController do
include StubENV
- let(:json_response) { JSON.parse(response.body) }
let(:metrics_multiproc_dir) { Dir.mktmpdir }
let(:whitelisted_ip) { '127.0.0.1' }
let(:whitelisted_ip_range) { '10.0.0.0/24' }
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 44500d3cde3..45aebd1554c 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -160,7 +160,7 @@ describe Projects::BlobController do
it 'renders diff context lines Gitlab::Diff::Line array' do
do_get(since: 1, to: 2, offset: 0, from_merge_request: true)
- lines = JSON.parse(response.body)
+ lines = json_response
expect(lines.size).to eq(diff_lines.size)
lines.each do |line|
@@ -173,7 +173,7 @@ describe Projects::BlobController do
it 'handles full being true' do
do_get(full: true, from_merge_request: true)
- lines = JSON.parse(response.body)
+ lines = json_response
expect(lines.size).to eq(diff_lines.size)
end
diff --git a/spec/controllers/projects/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb
index c07afc57aea..543479d8dd5 100644
--- a/spec/controllers/projects/boards_controller_spec.rb
+++ b/spec/controllers/projects/boards_controller_spec.rb
@@ -69,10 +69,8 @@ describe Projects::BoardsController do
list_boards format: :json
- parsed_response = JSON.parse(response.body)
-
expect(response).to match_response_schema('boards')
- expect(parsed_response.length).to eq 2
+ expect(json_response.length).to eq 2
end
context 'with unauthorized user' do
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index b30966e70a7..f5bcea4a097 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -495,10 +495,8 @@ describe Projects::BranchesController do
search: 'master'
}
- parsed_response = JSON.parse(response.body)
-
- expect(parsed_response.length).to eq 1
- expect(parsed_response.first).to eq 'master'
+ expect(json_response.length).to eq 1
+ expect(json_response.first).to eq 'master'
end
end
@@ -591,8 +589,7 @@ describe Projects::BranchesController do
end
it 'returns the commit counts behind and ahead of default branch' do
- parsed_response = JSON.parse(response.body)
- expect(parsed_response).to eq(
+ expect(json_response).to eq(
"fix" => { "behind" => 29, "ahead" => 2 },
"branch-merged" => { "behind" => 1, "ahead" => 0 },
"add-pdf-file" => { "behind" => 0, "ahead" => 3 }
diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb
index b5c6382a26d..58a1d96d010 100644
--- a/spec/controllers/projects/commit_controller_spec.rb
+++ b/spec/controllers/projects/commit_controller_spec.rb
@@ -378,8 +378,8 @@ describe Projects::CommitController do
get_pipelines(id: commit.id, format: :json)
expect(response).to be_ok
- expect(JSON.parse(response.body)['pipelines']).not_to be_empty
- expect(JSON.parse(response.body)['count']['all']).to eq 1
+ expect(json_response['pipelines']).not_to be_empty
+ expect(json_response['count']['all']).to eq 1
expect(response).to include_pagination_headers
end
end
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index 92380a2bf09..48a92a772dc 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -302,8 +302,7 @@ describe Projects::CompareController do
signatures_request
expect(response).to have_gitlab_http_status(200)
- parsed_body = JSON.parse(response.body)
- signatures = parsed_body['signatures']
+ signatures = json_response['signatures']
expect(signatures.size).to eq(1)
expect(signatures.first['commit_sha']).to eq(signature_commit.sha)
@@ -332,8 +331,7 @@ describe Projects::CompareController do
signatures_request
expect(response).to have_gitlab_http_status(200)
- parsed_body = JSON.parse(response.body)
- expect(parsed_body['signatures']).to be_empty
+ expect(json_response['signatures']).to be_empty
end
end
@@ -345,8 +343,7 @@ describe Projects::CompareController do
signatures_request
expect(response).to have_gitlab_http_status(200)
- parsed_body = JSON.parse(response.body)
- expect(parsed_body['signatures']).to be_empty
+ expect(json_response['signatures']).to be_empty
end
end
end
diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb
index fcd14f13863..ccad76eaddd 100644
--- a/spec/controllers/projects/deploy_keys_controller_spec.rb
+++ b/spec/controllers/projects/deploy_keys_controller_spec.rb
@@ -52,12 +52,10 @@ describe Projects::DeployKeysController do
it 'returns json in a correct format' do
get :index, params: params.merge(format: :json)
- json = JSON.parse(response.body)
-
- expect(json.keys).to match_array(%w(enabled_keys available_project_keys public_keys))
- expect(json['enabled_keys'].count).to eq(1)
- expect(json['available_project_keys'].count).to eq(1)
- expect(json['public_keys'].count).to eq(1)
+ expect(json_response.keys).to match_array(%w(enabled_keys available_project_keys public_keys))
+ expect(json_response['enabled_keys'].count).to eq(1)
+ expect(json_response['available_project_keys'].count).to eq(1)
+ expect(json_response['public_keys'].count).to eq(1)
end
end
end
diff --git a/spec/controllers/projects/discussions_controller_spec.rb b/spec/controllers/projects/discussions_controller_spec.rb
index 4c29162cd0f..e30b28a4bd5 100644
--- a/spec/controllers/projects/discussions_controller_spec.rb
+++ b/spec/controllers/projects/discussions_controller_spec.rb
@@ -112,7 +112,7 @@ describe Projects::DiscussionsController do
it "returns the name of the resolving user" do
post :resolve, params: request_params
- expect(JSON.parse(response.body)['resolved_by']['name']).to eq(user.name)
+ expect(json_response['resolved_by']['name']).to eq(user.name)
end
it "returns status 200" do
@@ -135,7 +135,7 @@ describe Projects::DiscussionsController do
it "returns truncated diff lines" do
post :resolve, params: request_params
- expect(JSON.parse(response.body)['truncated_diff_lines']).to be_present
+ expect(json_response['truncated_diff_lines']).to be_present
end
end
end
diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb
index fdef9bc5638..45328482ad7 100644
--- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb
+++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb
@@ -176,7 +176,7 @@ describe Projects::Environments::PrometheusApiController do
def environment_params(params = {})
{
id: environment.id.to_s,
- namespace_id: project.namespace.name,
+ namespace_id: project.namespace.full_path,
project_id: project.name,
proxy_path: 'query',
query: '1'
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index 4c2c6160c62..ebbbebf1bc0 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
describe Projects::EnvironmentsController do
+ include MetricsDashboardHelpers
+
set(:user) { create(:user) }
set(:project) { create(:project) }
@@ -445,131 +447,186 @@ describe Projects::EnvironmentsController do
end
end
- describe 'metrics_dashboard' do
- context 'when prometheus endpoint is disabled' do
- before do
- stub_feature_flags(environment_metrics_use_prometheus_endpoint: false)
- end
+ describe 'GET #metrics_dashboard' do
+ shared_examples_for 'correctly formatted response' do |status_code|
+ it 'returns a json object with the correct keys' do
+ get :metrics_dashboard, params: environment_params(dashboard_params)
- it 'responds with status code 403' do
- get :metrics_dashboard, params: environment_params(format: :json)
+ # Exlcude `all_dashboards` to handle separately.
+ found_keys = json_response.keys - ['all_dashboards']
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response).to have_gitlab_http_status(status_code)
+ expect(found_keys).to contain_exactly(*expected_keys)
end
end
- shared_examples_for '200 response' do |contains_all_dashboards: false|
+ shared_examples_for '200 response' do
let(:expected_keys) { %w(dashboard status) }
- before do
- expected_keys << 'all_dashboards' if contains_all_dashboards
- end
-
- it 'returns a json representation of the environment dashboard' do
- get :metrics_dashboard, params: environment_params(dashboard_params)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.keys).to contain_exactly(*expected_keys)
- expect(json_response['dashboard']).to be_an_instance_of(Hash)
- end
+ it_behaves_like 'correctly formatted response', :ok
end
- shared_examples_for 'error response' do |status_code, contains_all_dashboards: false|
+ shared_examples_for 'error response' do |status_code|
let(:expected_keys) { %w(message status) }
- before do
- expected_keys << 'all_dashboards' if contains_all_dashboards
- end
+ it_behaves_like 'correctly formatted response', status_code
+ end
- it 'returns an error response' do
+ shared_examples_for 'includes all dashboards' do
+ it 'includes info for all findable dashboard' do
get :metrics_dashboard, params: environment_params(dashboard_params)
- expect(response).to have_gitlab_http_status(status_code)
- expect(json_response.keys).to contain_exactly(*expected_keys)
+ expect(json_response).to have_key('all_dashboards')
+ expect(json_response['all_dashboards']).to be_an_instance_of(Array)
+ expect(json_response['all_dashboards']).to all( include('path', 'default', 'display_name') )
end
end
- shared_examples_for 'has all dashboards' do
- it 'includes an index of all available dashboards' do
+ shared_examples_for 'the default dashboard' do
+ all_dashboards = Feature.enabled?(:environment_metrics_show_multiple_dashboards)
+
+ it_behaves_like '200 response'
+ it_behaves_like 'includes all dashboards' if all_dashboards
+
+ it 'is the default dashboard' do
get :metrics_dashboard, params: environment_params(dashboard_params)
- expect(json_response.keys).to include('all_dashboards')
- expect(json_response['all_dashboards']).to be_an_instance_of(Array)
- expect(json_response['all_dashboards']).to all( include('path', 'default') )
+ expect(json_response['dashboard']['dashboard']).to eq('Environment metrics')
end
end
- context 'when multiple dashboards is disabled' do
- before do
- stub_feature_flags(environment_metrics_show_multiple_dashboards: false)
- end
+ shared_examples_for 'the specified dashboard' do |expected_dashboard|
+ it_behaves_like '200 response'
+ it_behaves_like 'includes all dashboards'
- let(:dashboard_params) { { format: :json } }
+ it 'has the correct name' do
+ get :metrics_dashboard, params: environment_params(dashboard_params)
- it_behaves_like '200 response'
+ dashboard_name = json_response['dashboard']['dashboard']
- context 'when the dashboard could not be provided' do
+ # 'Environment metrics' is the default dashboard.
+ expect(dashboard_name).not_to eq('Environment metrics')
+ expect(dashboard_name).to eq(expected_dashboard)
+ end
+
+ context 'when the dashboard cannot not be processed' do
before do
allow(YAML).to receive(:safe_load).and_return({})
end
it_behaves_like 'error response', :unprocessable_entity
end
-
- context 'when a dashboard param is specified' do
- let(:dashboard_params) { { format: :json, dashboard: '.gitlab/dashboards/not_there_dashboard.yml' } }
-
- it_behaves_like '200 response'
- end
end
- context 'when multiple dashboards is enabled' do
- let(:dashboard_params) { { format: :json } }
+ shared_examples_for 'the default dynamic dashboard' do
+ it_behaves_like '200 response'
- it_behaves_like '200 response', contains_all_dashboards: true
- it_behaves_like 'has all dashboards'
+ it 'contains only the Memory and CPU charts' do
+ get :metrics_dashboard, params: environment_params(dashboard_params)
- context 'when a dashboard could not be provided' do
- before do
- allow(YAML).to receive(:safe_load).and_return({})
- end
+ dashboard = json_response['dashboard']
+ panel_group = dashboard['panel_groups'].first
+ titles = panel_group['panels'].map { |panel| panel['title'] }
- it_behaves_like 'error response', :unprocessable_entity, contains_all_dashboards: true
- it_behaves_like 'has all dashboards'
+ expect(dashboard['dashboard']).to be_nil
+ expect(dashboard['panel_groups'].length).to eq 1
+ expect(panel_group['group']).to be_nil
+ expect(titles).to eq ['Memory Usage (Total)', 'Core Usage (Total)']
end
+ end
- context 'when a dashboard param is specified' do
- let(:dashboard_params) { { format: :json, dashboard: '.gitlab/dashboards/test.yml' } }
+ shared_examples_for 'dashboard can be specified' do
+ context 'when dashboard is specified' do
+ let(:dashboard_path) { '.gitlab/dashboards/test.yml' }
+ let(:dashboard_params) { { format: :json, dashboard: dashboard_path } }
+
+ it_behaves_like 'error response', :not_found
- context 'when the dashboard is available' do
+ context 'when the project dashboard is available' do
let(:dashboard_yml) { fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') }
- let(:dashboard_file) { { '.gitlab/dashboards/test.yml' => dashboard_yml } }
- let(:project) { create(:project, :custom_repo, files: dashboard_file) }
+ let(:project) { project_with_dashboard(dashboard_path, dashboard_yml) }
let(:environment) { create(:environment, name: 'production', project: project) }
- it_behaves_like '200 response', contains_all_dashboards: true
- it_behaves_like 'has all dashboards'
+ it_behaves_like 'the specified dashboard', 'Test Dashboard'
end
- context 'when the dashboard does not exist' do
- it_behaves_like 'error response', :not_found, contains_all_dashboards: true
- it_behaves_like 'has all dashboards'
+ context 'when the specified dashboard is the default dashboard' do
+ let(:dashboard_path) { Gitlab::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH }
+
+ it_behaves_like 'the default dashboard'
end
end
+ end
- context 'when the dashboard is intended for embedding' do
+ shared_examples_for 'dashboard can be embedded' do
+ context 'when the embedded flag is included' do
let(:dashboard_params) { { format: :json, embedded: true } }
- it_behaves_like '200 response'
+ it_behaves_like 'the default dynamic dashboard'
- context 'when a dashboard path is provided' do
- let(:dashboard_params) { { format: :json, dashboard: '.gitlab/dashboards/test.yml', embedded: true } }
+ context 'when the dashboard is specified' do
+ let(:dashboard_params) { { format: :json, embedded: true, dashboard: '.gitlab/dashboards/fake.yml' } }
- # The dashboard path should simple be ignored.
- it_behaves_like '200 response'
+ # The dashboard param should be ignored.
+ it_behaves_like 'the default dynamic dashboard'
end
end
end
+
+ shared_examples_for 'dashboard cannot be specified' do
+ context 'when dashboard is specified' do
+ let(:dashboard_params) { { format: :json, dashboard: '.gitlab/dashboards/test.yml' } }
+
+ it_behaves_like 'the default dashboard'
+ end
+ end
+
+ shared_examples_for 'dashboard cannot be embedded' do
+ context 'when the embedded flag is included' do
+ let(:dashboard_params) { { format: :json, embedded: true } }
+
+ it_behaves_like 'the default dashboard'
+ end
+ end
+
+ let(:dashboard_params) { { format: :json } }
+
+ it_behaves_like 'the default dashboard'
+ it_behaves_like 'dashboard can be specified'
+ it_behaves_like 'dashboard can be embedded'
+
+ context 'when multiple dashboards is enabled and embedding metrics is disabled' do
+ before do
+ stub_feature_flags(gfm_embedded_metrics: false)
+ end
+
+ it_behaves_like 'the default dashboard'
+ it_behaves_like 'dashboard can be specified'
+ it_behaves_like 'dashboard cannot be embedded'
+ end
+
+ context 'when multiple dashboards is disabled and embedding metrics is enabled' do
+ before do
+ stub_feature_flags(environment_metrics_show_multiple_dashboards: false)
+ end
+
+ it_behaves_like 'the default dashboard'
+ it_behaves_like 'dashboard cannot be specified'
+ it_behaves_like 'dashboard can be embedded'
+ end
+
+ context 'when multiple dashboards and embedding metrics are disabled' do
+ before do
+ stub_feature_flags(
+ environment_metrics_show_multiple_dashboards: false,
+ gfm_embedded_metrics: false
+ )
+ end
+
+ it_behaves_like 'the default dashboard'
+ it_behaves_like 'dashboard cannot be specified'
+ it_behaves_like 'dashboard cannot be embedded'
+ end
end
describe 'GET #search' do
diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb
index 538dbb5ad0b..a493985f8a0 100644
--- a/spec/controllers/projects/find_file_controller_spec.rb
+++ b/spec/controllers/projects/find_file_controller_spec.rb
@@ -53,10 +53,9 @@ describe Projects::FindFileController do
it 'returns an array of file path list' do
go
- json = JSON.parse(response.body)
is_expected.to respond_with(:success)
- expect(json).not_to eq(nil)
- expect(json.length).to be >= 0
+ expect(json_response).not_to eq(nil)
+ expect(json_response.length).to be >= 0
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index bc5e0b4671e..32d14dce936 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -444,7 +444,7 @@ describe Projects::IssuesController do
it 'renders json with recaptcha_html' do
subject
- expect(JSON.parse(response.body)).to have_key('recaptcha_html')
+ expect(json_response).to have_key('recaptcha_html')
end
end
end
@@ -484,10 +484,8 @@ describe Projects::IssuesController do
it 'returns last edited time' do
go(id: issue.iid)
- data = JSON.parse(response.body)
-
- expect(data).to include('updated_at')
- expect(data['updated_at']).to eq(issue.last_edited_at.to_time.iso8601)
+ expect(json_response).to include('updated_at')
+ expect(json_response['updated_at']).to eq(issue.last_edited_at.to_time.iso8601)
end
end
@@ -520,10 +518,8 @@ describe Projects::IssuesController do
it 'returns the necessary data' do
go(id: issue.iid)
- data = JSON.parse(response.body)
-
- expect(data).to include('title_text', 'description', 'description_text')
- expect(data).to include('task_status', 'lock_version')
+ expect(json_response).to include('title_text', 'description', 'description_text')
+ expect(json_response).to include('task_status', 'lock_version')
end
end
end
@@ -692,9 +688,7 @@ describe Projects::IssuesController do
update_issue(issue_params: { assignee_ids: [assignee.id] })
- body = JSON.parse(response.body)
-
- expect(body['assignees'].first.keys)
+ expect(json_response['assignees'].first.keys)
.to match_array(%w(id name username avatar_url state web_url))
end
end
@@ -1314,7 +1308,7 @@ describe Projects::IssuesController do
it 'filters notes that the user should not see' do
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
- expect(JSON.parse(response.body).count).to eq(1)
+ expect(json_response.count).to eq(1)
end
it 'does not result in N+1 queries' do
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
index 13a28b738ca..d940d226176 100644
--- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -112,7 +112,7 @@ describe Projects::MergeRequests::DiffsController do
it 'only renders the diffs for the path given' do
diff_for_path(old_path: existing_path, new_path: existing_path)
- paths = JSON.parse(response.body)["diff_files"].map { |file| file['new_path'] }
+ paths = json_response["diff_files"].map { |file| file['new_path'] }
expect(paths).to include(existing_path)
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index cc6adc0a6c6..f11880122b1 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -242,9 +242,7 @@ describe Projects::MergeRequestsController do
update_merge_request({ assignee_ids: [assignee.id] }, format: :json)
- body = JSON.parse(response.body)
-
- expect(body['assignees']).to all(include(*%w(name username avatar_url id state web_url)))
+ expect(json_response['assignees']).to all(include(*%w(name username avatar_url id state web_url)))
end
end
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 1db1963476c..98aea9056dc 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -29,7 +29,7 @@ describe Projects::NotesController do
}
end
- let(:parsed_response) { JSON.parse(response.body).with_indifferent_access }
+ let(:parsed_response) { json_response.with_indifferent_access }
let(:note_json) { parsed_response[:notes].first }
before do
@@ -614,7 +614,7 @@ describe Projects::NotesController do
it "returns the name of the resolving user" do
post :resolve, params: request_params.merge(html: true)
- expect(JSON.parse(response.body)["resolved_by"]).to eq(user.name)
+ expect(json_response["resolved_by"]).to eq(user.name)
end
it "returns status 200" do
diff --git a/spec/controllers/projects/templates_controller_spec.rb b/spec/controllers/projects/templates_controller_spec.rb
index 9e7d34b10c0..d5ef2b0e114 100644
--- a/spec/controllers/projects/templates_controller_spec.rb
+++ b/spec/controllers/projects/templates_controller_spec.rb
@@ -7,7 +7,6 @@ describe Projects::TemplatesController do
let(:user) { create(:user) }
let(:file_path_1) { '.gitlab/issue_templates/issue_template.md' }
let(:file_path_2) { '.gitlab/merge_request_templates/merge_request_template.md' }
- let(:body) { JSON.parse(response.body) }
let!(:file_1) { project.repository.create_file(user, file_path_1, 'issue content', message: 'message', branch_name: 'master') }
let!(:file_2) { project.repository.create_file(user, file_path_2, 'merge request content', message: 'message', branch_name: 'master') }
@@ -17,8 +16,8 @@ describe Projects::TemplatesController do
get(:show, params: { namespace_id: project.namespace, template_type: 'issue', key: 'issue_template', project_id: project }, format: :json)
expect(response.status).to eq(200)
- expect(body['name']).to eq('issue_template')
- expect(body['content']).to eq('issue content')
+ expect(json_response['name']).to eq('issue_template')
+ expect(json_response['content']).to eq('issue content')
end
end
@@ -27,8 +26,8 @@ describe Projects::TemplatesController do
get(:show, params: { namespace_id: project.namespace, template_type: 'merge_request', key: 'merge_request_template', project_id: project }, format: :json)
expect(response.status).to eq(200)
- expect(body['name']).to eq('merge_request_template')
- expect(body['content']).to eq('merge request content')
+ expect(json_response['name']).to eq('merge_request_template')
+ expect(json_response['content']).to eq('merge request content')
end
end
diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb
index f2e0b5e5c1d..a7e5a79b51d 100644
--- a/spec/controllers/projects/wikis_controller_spec.rb
+++ b/spec/controllers/projects/wikis_controller_spec.rb
@@ -103,7 +103,7 @@ describe Projects::WikisController do
it 'renders json in a correct format' do
post :preview_markdown, params: { namespace_id: project.namespace, project_id: project, id: 'page/path', text: '*Markdown* text' }
- expect(JSON.parse(response.body).keys).to match_array(%w(body references))
+ expect(json_response.keys).to match_array(%w(body references))
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 4e1cac67d23..083a1c1383a 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -740,20 +740,18 @@ describe ProjectsController do
it 'gets a list of branches and tags' do
get :refs, params: { namespace_id: project.namespace, id: project, sort: 'updated_desc' }
- parsed_body = JSON.parse(response.body)
- expect(parsed_body['Branches']).to include('master')
- expect(parsed_body['Tags'].first).to eq('v1.1.0')
- expect(parsed_body['Tags'].last).to eq('v1.0.0')
- expect(parsed_body['Commits']).to be_nil
+ expect(json_response['Branches']).to include('master')
+ expect(json_response['Tags'].first).to eq('v1.1.0')
+ expect(json_response['Tags'].last).to eq('v1.0.0')
+ expect(json_response['Commits']).to be_nil
end
it "gets a list of branches, tags and commits" do
get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
- parsed_body = JSON.parse(response.body)
- expect(parsed_body["Branches"]).to include("master")
- expect(parsed_body["Tags"]).to include("v1.0.0")
- expect(parsed_body["Commits"]).to include("123456")
+ expect(json_response["Branches"]).to include("master")
+ expect(json_response["Tags"]).to include("v1.0.0")
+ expect(json_response["Commits"]).to include("123456")
end
context "when preferred language is Japanese" do
@@ -765,10 +763,9 @@ describe ProjectsController do
it "gets a list of branches, tags and commits" do
get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
- parsed_body = JSON.parse(response.body)
- expect(parsed_body["Branches"]).to include("master")
- expect(parsed_body["Tags"]).to include("v1.0.0")
- expect(parsed_body["Commits"]).to include("123456")
+ expect(json_response["Branches"]).to include("master")
+ expect(json_response["Tags"]).to include("v1.0.0")
+ expect(json_response["Commits"]).to include("123456")
end
end
@@ -797,7 +794,7 @@ describe ProjectsController do
it 'renders json in a correct format' do
post :preview_markdown, params: { namespace_id: public_project.namespace, id: public_project, text: '*Markdown* text' }
- expect(JSON.parse(response.body).keys).to match_array(%w(body references))
+ expect(json_response.keys).to match_array(%w(body references))
end
context 'when not authorized' do
@@ -821,8 +818,6 @@ describe ProjectsController do
text: issue.to_reference
}
- json_response = JSON.parse(response.body)
-
expect(json_response['body']).to match(/\##{issue.iid} \(closed\)/)
end
@@ -833,8 +828,6 @@ describe ProjectsController do
text: merge_request.to_reference
}
- json_response = JSON.parse(response.body)
-
expect(json_response['body']).to match(/\!#{merge_request.iid} \(closed\)/)
end
end
diff --git a/spec/controllers/snippets/notes_controller_spec.rb b/spec/controllers/snippets/notes_controller_spec.rb
index 586d59c2d09..652533ac49f 100644
--- a/spec/controllers/snippets/notes_controller_spec.rb
+++ b/spec/controllers/snippets/notes_controller_spec.rb
@@ -26,7 +26,7 @@ describe Snippets::NotesController do
end
it "returns not empty array of notes" do
- expect(JSON.parse(response.body)["notes"].empty?).to be_falsey
+ expect(json_response["notes"].empty?).to be_falsey
end
end
@@ -97,7 +97,7 @@ describe Snippets::NotesController do
it "returns 1 note" do
get :index, params: { snippet_id: private_snippet }
- expect(JSON.parse(response.body)['notes'].count).to eq(1)
+ expect(json_response['notes'].count).to eq(1)
end
end
end
@@ -114,7 +114,7 @@ describe Snippets::NotesController do
it "does not return any note" do
get :index, params: { snippet_id: public_snippet }
- expect(JSON.parse(response.body)['notes'].count).to eq(0)
+ expect(json_response['notes'].count).to eq(0)
end
end
end
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 3aba02bf3ff..b0092bc8994 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -622,7 +622,7 @@ describe SnippetsController do
post :preview_markdown, params: { id: snippet, text: '*Markdown* text' }
- expect(JSON.parse(response.body).keys).to match_array(%w(body references))
+ expect(json_response.keys).to match_array(%w(body references))
end
end
end
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index c3d6ea9cbcd..8b8d4c57000 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -291,7 +291,7 @@ describe UsersController do
it 'response with snippets json data' do
get :snippets, params: { username: user.username }, format: :json
expect(response).to have_gitlab_http_status(200)
- expect(JSON.parse(response.body)).to have_key('html')
+ expect(json_response).to have_key('html')
end
end
diff --git a/spec/factories/ci/bridge.rb b/spec/factories/ci/bridge.rb
index b1d82b98411..7cb5900f2b7 100644
--- a/spec/factories/ci/bridge.rb
+++ b/spec/factories/ci/bridge.rb
@@ -1,6 +1,6 @@
FactoryBot.define do
factory :ci_bridge, class: Ci::Bridge do
- name ' bridge'
+ name 'bridge'
stage 'test'
stage_idx 0
ref 'master'
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 743ec322885..7d7738a30c8 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -306,34 +306,18 @@ FactoryBot.define do
factory :redmine_project, parent: :project do
has_external_issue_tracker true
- after :create do |project|
- project.create_redmine_service(
- active: true,
- properties: {
- 'project_url' => 'http://redmine/projects/project_name_in_redmine',
- 'issues_url' => 'http://redmine/projects/project_name_in_redmine/issues/:id',
- 'new_issue_url' => 'http://redmine/projects/project_name_in_redmine/issues/new'
- }
- )
- end
+ redmine_service
end
factory :youtrack_project, parent: :project do
has_external_issue_tracker true
- after :create do |project|
- project.create_youtrack_service(
- active: true,
- properties: {
- 'project_url' => 'http://youtrack/projects/project_guid_in_youtrack',
- 'issues_url' => 'http://youtrack/issues/:id'
- }
- )
- end
+ youtrack_service
end
factory :jira_project, parent: :project do
has_external_issue_tracker true
+
jira_service
end
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index cd1d2c33373..daf842e3075 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -79,14 +79,12 @@ FactoryBot.define do
trait :issue_tracker do
properties(
project_url: 'http://issue-tracker.example.com',
- issues_url: 'http://issue-tracker.example.com',
+ issues_url: 'http://issue-tracker.example.com/issues/:id',
new_issue_url: 'http://issue-tracker.example.com'
)
end
- factory :jira_cloud_service, class: JiraService do
- project
- active true
+ trait :jira_cloud_service do
properties(
url: 'https://mysite.atlassian.net',
username: 'jira_user',
diff --git a/spec/factories/services_data.rb b/spec/factories/services_data.rb
index 387e130a743..5a3639895b6 100644
--- a/spec/factories/services_data.rb
+++ b/spec/factories/services_data.rb
@@ -1,18 +1,12 @@
# frozen_string_literal: true
+# these factories should never be called directly, they are used when creating services
FactoryBot.define do
factory :jira_tracker_data do
service
- url 'http://jira.example.com'
- api_url 'http://api-jira.example.com'
- username 'jira_username'
- password 'jira_password'
end
factory :issue_tracker_data do
service
- project_url 'http://issuetracker.example.com'
- issues_url 'http://issues.example.com'
- new_issue_url 'http://new-issue.example.com'
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 4a9037afb43..518b3625348 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -400,35 +400,16 @@ describe 'Admin updates settings' do
.to have_content "The form contains the following error: Polling interval multiplier must be greater than or equal to 0"
end
- context 'When pages_auto_ssl is enabled' do
- before do
- stub_feature_flags(pages_auto_ssl: true)
- visit preferences_admin_application_settings_path
- end
-
- it "Change Pages Let's Encrypt settings" do
- page.within('.as-pages') do
- fill_in 'Email', with: 'my@test.example.com'
- check "I have read and agree to the Let's Encrypt Terms of Service"
- click_button 'Save changes'
- end
-
- expect(current_settings.lets_encrypt_notification_email).to eq 'my@test.example.com'
- expect(current_settings.lets_encrypt_terms_of_service_accepted).to eq true
- end
- end
-
- context 'When pages_auto_ssl is disabled' do
- before do
- stub_feature_flags(pages_auto_ssl: false)
- visit preferences_admin_application_settings_path
+ it "Change Pages Let's Encrypt settings" do
+ visit preferences_admin_application_settings_path
+ page.within('.as-pages') do
+ fill_in 'Email', with: 'my@test.example.com'
+ check "I have read and agree to the Let's Encrypt Terms of Service"
+ click_button 'Save changes'
end
- it "Doesn't show Let's Encrypt options" do
- page.within('.as-pages') do
- expect(page).not_to have_content('Email')
- end
- end
+ expect(current_settings.lets_encrypt_notification_email).to eq 'my@test.example.com'
+ expect(current_settings.lets_encrypt_terms_of_service_accepted).to eq true
end
end
diff --git a/spec/features/markdown/mermaid_spec.rb b/spec/features/markdown/mermaid_spec.rb
index 7008b361394..e3bcaca737e 100644
--- a/spec/features/markdown/mermaid_spec.rb
+++ b/spec/features/markdown/mermaid_spec.rb
@@ -21,4 +21,22 @@ describe 'Mermaid rendering', :js do
expect(page).to have_selector('svg text', text: label)
end
end
+
+ it 'renders linebreaks in Mermaid diagrams' do
+ description = <<~MERMAID
+ ```mermaid
+ graph TD;
+ A(Line 1<br>Line 2)-->B(Line 1<br/>Line 2);
+ C(Line 1<br />Line 2)-->D(Line 1<br />Line 2);
+ ```
+ MERMAID
+
+ project = create(:project, :public)
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ expected = '<text><tspan xml:space="preserve" dy="1em" x="1">Line 1</tspan><tspan xml:space="preserve" dy="1em" x="1">Line 2</tspan></text>'
+ expect(page.html.scan(expected).count).to be(4)
+ end
end
diff --git a/spec/features/merge_request/user_creates_merge_request_spec.rb b/spec/features/merge_request/user_creates_merge_request_spec.rb
index d05ef2a8f12..2a70cbb2a72 100644
--- a/spec/features/merge_request/user_creates_merge_request_spec.rb
+++ b/spec/features/merge_request/user_creates_merge_request_spec.rb
@@ -78,7 +78,7 @@ describe "User creates a merge request", :js do
click_button("Submit merge request")
- expect(page).to have_content(title).and have_content("Request to merge #{user.namespace.name}:#{source_branch} into master")
+ expect(page).to have_content(title).and have_content("Request to merge #{user.namespace.path}:#{source_branch} into master")
end
end
end
diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb
index e0fa9dbb5fa..e4b02408b49 100644
--- a/spec/features/projects/files/user_edits_files_spec.rb
+++ b/spec/features/projects/files/user_edits_files_spec.rb
@@ -162,6 +162,7 @@ describe 'Projects > Files > User edits files', :js do
expect_fork_status
+ expect(page).to have_css('.ide-sidebar-project-title', text: "#{project2.name} #{user.namespace.full_path}/#{project2.path}")
expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore')
end
diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb
index 7c71b4c52e0..26b94bf58b2 100644
--- a/spec/features/projects/fork_spec.rb
+++ b/spec/features/projects/fork_spec.rb
@@ -50,7 +50,7 @@ describe 'Project fork' do
click_link('New merge request')
end
- expect(current_path).to have_content(/#{user.namespace.name}/i)
+ expect(current_path).to have_content(/#{user.namespace.path}/i)
end
it 'shows avatars when Gravatar is disabled' do
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index 033e1afe866..fe7b4b759a8 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -3,300 +3,330 @@ require 'spec_helper'
describe 'New project' do
include Select2Helper
- let(:user) { create(:admin) }
+ context 'as a user' do
+ let(:user) { create(:user) }
- before do
- sign_in(user)
- end
+ before do
+ sign_in(user)
+ end
- it 'shows "New project" page', :js do
- visit new_project_path
+ it 'shows a message if multiple levels are restricted' do
+ Gitlab::CurrentSettings.update!(
+ restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE, Gitlab::VisibilityLevel::INTERNAL]
+ )
- expect(page).to have_content('Project name')
- expect(page).to have_content('Project URL')
- expect(page).to have_content('Project slug')
+ visit new_project_path
- find('#import-project-tab').click
+ expect(page).to have_content 'Other visibility settings have been disabled by the administrator.'
+ end
- expect(page).to have_link('GitHub')
- expect(page).to have_link('Bitbucket')
- expect(page).to have_link('GitLab.com')
- expect(page).to have_link('Google Code')
- expect(page).to have_button('Repo by URL')
- expect(page).to have_link('GitLab export')
- end
+ it 'shows a message if all levels are restricted' do
+ Gitlab::CurrentSettings.update!(
+ restricted_visibility_levels: Gitlab::VisibilityLevel.values
+ )
- describe 'manifest import option' do
- before do
visit new_project_path
- find('#import-project-tab').click
+ expect(page).to have_content 'Visibility settings have been disabled by the administrator.'
end
+ end
- context 'when using postgres', :postgresql do
- it { expect(page).to have_link('Manifest file') }
- end
+ context 'as an admin' do
+ let(:user) { create(:admin) }
- context 'when using mysql', :mysql do
- it { expect(page).not_to have_link('Manifest file') }
+ before do
+ sign_in(user)
end
- end
- context 'Visibility level selector', :js do
- Gitlab::VisibilityLevel.options.each do |key, level|
- it "sets selector to #{key}" do
- stub_application_setting(default_project_visibility: level)
+ it 'shows "New project" page', :js do
+ visit new_project_path
- visit new_project_path
- page.within('#blank-project-pane') do
- expect(find_field("project_visibility_level_#{level}")).to be_checked
- end
- end
+ expect(page).to have_content('Project name')
+ expect(page).to have_content('Project URL')
+ expect(page).to have_content('Project slug')
- it "saves visibility level #{level} on validation error" do
- visit new_project_path
+ find('#import-project-tab').click
- choose(s_(key))
- click_button('Create project')
- page.within('#blank-project-pane') do
- expect(find_field("project_visibility_level_#{level}")).to be_checked
- end
- end
+ expect(page).to have_link('GitHub')
+ expect(page).to have_link('Bitbucket')
+ expect(page).to have_link('GitLab.com')
+ expect(page).to have_link('Google Code')
+ expect(page).to have_button('Repo by URL')
+ expect(page).to have_link('GitLab export')
end
- context 'when group visibility is private but default is internal' do
+ describe 'manifest import option' do
before do
- stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
+ visit new_project_path
+
+ find('#import-project-tab').click
end
- it 'has private selected' do
- group = create(:group, visibility_level: Gitlab::VisibilityLevel::PRIVATE)
- visit new_project_path(namespace_id: group.id)
+ context 'when using postgres', :postgresql do
+ it { expect(page).to have_link('Manifest file') }
+ end
- page.within('#blank-project-pane') do
- expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
- end
+ context 'when using mysql', :mysql do
+ it { expect(page).not_to have_link('Manifest file') }
end
end
- context 'when group visibility is public but user requests private' do
- before do
- stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
- end
+ context 'Visibility level selector', :js do
+ Gitlab::VisibilityLevel.options.each do |key, level|
+ it "sets selector to #{key}" do
+ stub_application_setting(default_project_visibility: level)
+
+ visit new_project_path
+ page.within('#blank-project-pane') do
+ expect(find_field("project_visibility_level_#{level}")).to be_checked
+ end
+ end
- it 'has private selected' do
- group = create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
+ it "saves visibility level #{level} on validation error" do
+ visit new_project_path
- page.within('#blank-project-pane') do
- expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
+ choose(s_(key))
+ click_button('Create project')
+ page.within('#blank-project-pane') do
+ expect(find_field("project_visibility_level_#{level}")).to be_checked
+ end
end
end
- end
- end
- context 'Readme selector' do
- it 'shows the initialize with Readme checkbox on "Blank project" tab' do
- visit new_project_path
+ context 'when group visibility is private but default is internal' do
+ before do
+ stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
+ end
- expect(page).to have_css('input#project_initialize_with_readme')
- expect(page).to have_content('Initialize repository with a README')
- end
+ it 'has private selected' do
+ group = create(:group, visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ visit new_project_path(namespace_id: group.id)
- it 'does not show the initialize with Readme checkbox on "Create from template" tab' do
- visit new_project_path
- find('#create-from-template-pane').click
- first('.choose-template').click
+ page.within('#blank-project-pane') do
+ expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
+ end
+ end
+ end
+
+ context 'when group visibility is public but user requests private' do
+ before do
+ stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
+ end
- page.within '.project-fields-form' do
- expect(page).not_to have_css('input#project_initialize_with_readme')
- expect(page).not_to have_content('Initialize repository with a README')
+ it 'has private selected' do
+ group = create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
+
+ page.within('#blank-project-pane') do
+ expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked
+ end
+ end
end
end
- it 'does not show the initialize with Readme checkbox on "Import project" tab' do
- visit new_project_path
- find('#import-project-tab').click
- first('.js-import-git-toggle-button').click
+ context 'Readme selector' do
+ it 'shows the initialize with Readme checkbox on "Blank project" tab' do
+ visit new_project_path
- page.within '.toggle-import-form' do
- expect(page).not_to have_css('input#project_initialize_with_readme')
- expect(page).not_to have_content('Initialize repository with a README')
+ expect(page).to have_css('input#project_initialize_with_readme')
+ expect(page).to have_content('Initialize repository with a README')
end
- end
- end
- context 'Namespace selector' do
- context 'with user namespace' do
- before do
+ it 'does not show the initialize with Readme checkbox on "Create from template" tab' do
visit new_project_path
+ find('#create-from-template-pane').click
+ first('.choose-template').click
+
+ page.within '.project-fields-form' do
+ expect(page).not_to have_css('input#project_initialize_with_readme')
+ expect(page).not_to have_content('Initialize repository with a README')
+ end
end
- it 'selects the user namespace' do
- page.within('#blank-project-pane') do
- namespace = find('#project_namespace_id')
+ it 'does not show the initialize with Readme checkbox on "Import project" tab' do
+ visit new_project_path
+ find('#import-project-tab').click
+ first('.js-import-git-toggle-button').click
- expect(namespace.text).to eq user.username
+ page.within '.toggle-import-form' do
+ expect(page).not_to have_css('input#project_initialize_with_readme')
+ expect(page).not_to have_content('Initialize repository with a README')
end
end
end
- context 'with group namespace' do
- let(:group) { create(:group, :private) }
+ context 'Namespace selector' do
+ context 'with user namespace' do
+ before do
+ visit new_project_path
+ end
- before do
- group.add_owner(user)
- visit new_project_path(namespace_id: group.id)
+ it 'selects the user namespace' do
+ page.within('#blank-project-pane') do
+ namespace = find('#project_namespace_id')
+
+ expect(namespace.text).to eq user.username
+ end
+ end
end
- it 'selects the group namespace' do
- page.within('#blank-project-pane') do
- namespace = find('#project_namespace_id option[selected]')
+ context 'with group namespace' do
+ let(:group) { create(:group, :private) }
- expect(namespace.text).to eq group.name
+ before do
+ group.add_owner(user)
+ visit new_project_path(namespace_id: group.id)
end
- end
- end
- context 'with subgroup namespace' do
- let(:group) { create(:group) }
- let(:subgroup) { create(:group, parent: group) }
+ it 'selects the group namespace' do
+ page.within('#blank-project-pane') do
+ namespace = find('#project_namespace_id option[selected]')
- before do
- group.add_maintainer(user)
- visit new_project_path(namespace_id: subgroup.id)
+ expect(namespace.text).to eq group.name
+ end
+ end
end
- it 'selects the group namespace' do
- page.within('#blank-project-pane') do
- namespace = find('#project_namespace_id option[selected]')
+ context 'with subgroup namespace' do
+ let(:group) { create(:group) }
+ let(:subgroup) { create(:group, parent: group) }
- expect(namespace.text).to eq subgroup.full_path
+ before do
+ group.add_maintainer(user)
+ visit new_project_path(namespace_id: subgroup.id)
end
- end
- end
- context 'when changing namespaces dynamically', :js do
- let(:public_group) { create(:group, :public) }
- let(:internal_group) { create(:group, :internal) }
- let(:private_group) { create(:group, :private) }
+ it 'selects the group namespace' do
+ page.within('#blank-project-pane') do
+ namespace = find('#project_namespace_id option[selected]')
- before do
- public_group.add_owner(user)
- internal_group.add_owner(user)
- private_group.add_owner(user)
- visit new_project_path(namespace_id: public_group.id)
+ expect(namespace.text).to eq subgroup.full_path
+ end
+ end
end
- it 'enables the correct visibility options' do
- select2(user.namespace_id, from: '#project_namespace_id')
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled
-
- select2(public_group.id, from: '#project_namespace_id')
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled
-
- select2(internal_group.id, from: '#project_namespace_id')
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled
-
- select2(private_group.id, from: '#project_namespace_id')
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).to be_disabled
- expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled
- end
- end
- end
+ context 'when changing namespaces dynamically', :js do
+ let(:public_group) { create(:group, :public) }
+ let(:internal_group) { create(:group, :internal) }
+ let(:private_group) { create(:group, :private) }
- context 'Import project options', :js do
- before do
- visit new_project_path
- find('#import-project-tab').click
+ before do
+ public_group.add_owner(user)
+ internal_group.add_owner(user)
+ private_group.add_owner(user)
+ visit new_project_path(namespace_id: public_group.id)
+ end
+
+ it 'enables the correct visibility options' do
+ select2(user.namespace_id, from: '#project_namespace_id')
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled
+
+ select2(public_group.id, from: '#project_namespace_id')
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled
+
+ select2(internal_group.id, from: '#project_namespace_id')
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled
+
+ select2(private_group.id, from: '#project_namespace_id')
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).to be_disabled
+ expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled
+ end
+ end
end
- context 'from git repository url, "Repo by URL"' do
+ context 'Import project options', :js do
before do
- first('.js-import-git-toggle-button').click
+ visit new_project_path
+ find('#import-project-tab').click
end
- it 'does not autocomplete sensitive git repo URL' do
- autocomplete = find('#project_import_url')['autocomplete']
+ context 'from git repository url, "Repo by URL"' do
+ before do
+ first('.js-import-git-toggle-button').click
+ end
+
+ it 'does not autocomplete sensitive git repo URL' do
+ autocomplete = find('#project_import_url')['autocomplete']
- expect(autocomplete).to eq('off')
- end
+ expect(autocomplete).to eq('off')
+ end
- it 'shows import instructions' do
- git_import_instructions = first('.js-toggle-content')
+ it 'shows import instructions' do
+ git_import_instructions = first('.js-toggle-content')
- expect(git_import_instructions).to be_visible
- expect(git_import_instructions).to have_content 'Git repository URL'
- end
+ expect(git_import_instructions).to be_visible
+ expect(git_import_instructions).to have_content 'Git repository URL'
+ end
- it 'keeps "Import project" tab open after form validation error' do
- collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace)
+ it 'keeps "Import project" tab open after form validation error' do
+ collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace)
- fill_in 'project_import_url', with: collision_project.http_url_to_repo
- fill_in 'project_name', with: collision_project.name
+ fill_in 'project_import_url', with: collision_project.http_url_to_repo
+ fill_in 'project_name', with: collision_project.name
- click_on 'Create project'
+ click_on 'Create project'
- expect(page).to have_css('#import-project-pane.active')
- expect(page).not_to have_css('.toggle-import-form.hide')
+ expect(page).to have_css('#import-project-pane.active')
+ expect(page).not_to have_css('.toggle-import-form.hide')
+ end
end
- end
- context 'from GitHub' do
- before do
- first('.js-import-github').click
- end
+ context 'from GitHub' do
+ before do
+ first('.js-import-github').click
+ end
- it 'shows import instructions' do
- expect(page).to have_content('Import repositories from GitHub')
- expect(current_path).to eq new_import_github_path
+ it 'shows import instructions' do
+ expect(page).to have_content('Import repositories from GitHub')
+ expect(current_path).to eq new_import_github_path
+ end
end
- end
- context 'from Google Code' do
- before do
- first('.import_google_code').click
- end
+ context 'from Google Code' do
+ before do
+ first('.import_google_code').click
+ end
- it 'shows import instructions' do
- expect(page).to have_content('Import projects from Google Code')
- expect(current_path).to eq new_import_google_code_path
+ it 'shows import instructions' do
+ expect(page).to have_content('Import projects from Google Code')
+ expect(current_path).to eq new_import_google_code_path
+ end
end
- end
- context 'from manifest file', :postgresql do
- before do
- first('.import_manifest').click
- end
+ context 'from manifest file', :postgresql do
+ before do
+ first('.import_manifest').click
+ end
- it 'shows import instructions' do
- expect(page).to have_content('Manifest file import')
- expect(current_path).to eq new_import_manifest_path
+ it 'shows import instructions' do
+ expect(page).to have_content('Manifest file import')
+ expect(current_path).to eq new_import_manifest_path
+ end
end
end
- end
- context 'Namespace selector' do
- context 'with group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do
- let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
+ context 'Namespace selector' do
+ context 'with group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do
+ let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
- before do
- group.add_developer(user)
- visit new_project_path(namespace_id: group.id)
- end
+ before do
+ group.add_developer(user)
+ visit new_project_path(namespace_id: group.id)
+ end
- it 'selects the group namespace' do
- page.within('#blank-project-pane') do
- namespace = find('#project_namespace_id option[selected]')
+ it 'selects the group namespace' do
+ page.within('#blank-project-pane') do
+ namespace = find('#project_namespace_id option[selected]')
- expect(namespace.text).to eq group.full_path
+ expect(namespace.text).to eq group.full_path
+ end
end
end
end
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 919859c145a..7c44680e9f7 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -66,7 +66,7 @@ describe 'Triggers', :js do
it 'edit "legacy" trigger and save' do
# Create new trigger without owner association, i.e. Legacy trigger
- create(:ci_trigger, owner: nil, project: @project)
+ create(:ci_trigger, owner: user, project: @project).update_attribute(:owner, nil)
visit project_settings_ci_cd_path(@project)
# See if the trigger can be edited and description is blank
@@ -127,17 +127,19 @@ describe 'Triggers', :js do
end
describe 'show triggers workflow' do
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: false)
+ end
+
it 'contains trigger description placeholder' do
expect(page.find('#trigger_description')['placeholder']).to eq 'Trigger description'
end
- it 'show "legacy" badge for legacy trigger' do
- create(:ci_trigger, owner: nil, project: @project)
+ it 'show "invalid" badge for legacy trigger' do
+ create(:ci_trigger, owner: user, project: @project).update_attribute(:owner, nil)
visit project_settings_ci_cd_path(@project)
- # See if trigger without owner (i.e. legacy) shows "legacy" badge and is editable
- expect(page.find('.triggers-list')).to have_content 'legacy'
- expect(page.find('.triggers-list')).to have_selector('a[title="Edit"]')
+ expect(page.find('.triggers-list')).to have_content 'invalid'
end
it 'show "invalid" badge for trigger with owner having insufficient permissions' do
@@ -149,6 +151,19 @@ describe 'Triggers', :js do
expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
end
+ it 'do not show "Edit" or full token for legacy trigger' do
+ create(:ci_trigger, owner: user, project: @project, description: trigger_title)
+ .update_attribute(:owner, nil)
+ visit project_settings_ci_cd_path(@project)
+
+ # See if trigger not owned shows only first few token chars and doesn't have copy-to-clipboard button
+ expect(page.find('.triggers-list')).to have_content(@project.triggers.first.token[0..3])
+ expect(page.find('.triggers-list')).not_to have_selector('button.btn-clipboard')
+
+ # See if trigger is non-editable
+ expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
+ end
+
it 'do not show "Edit" or full token for not owned trigger' do
# Create trigger with user different from current_user
create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
@@ -175,5 +190,56 @@ describe 'Triggers', :js do
expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
expect(page.find('.triggers-list')).to have_selector('a[title="Edit"]')
end
+
+ context 'when :use_legacy_pipeline_triggers feature flag is enabled' do
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: true)
+ end
+
+ it 'show "legacy" badge for legacy trigger' do
+ create(:ci_trigger, owner: nil, project: @project)
+ visit project_settings_ci_cd_path(@project)
+
+ # See if trigger without owner (i.e. legacy) shows "legacy" badge and is editable
+ expect(page.find('.triggers-list')).to have_content 'legacy'
+ expect(page.find('.triggers-list')).to have_selector('a[title="Edit"]')
+ end
+
+ it 'show "invalid" badge for trigger with owner having insufficient permissions' do
+ create(:ci_trigger, owner: guest_user, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
+
+ # See if trigger without owner (i.e. legacy) shows "legacy" badge and is non-editable
+ expect(page.find('.triggers-list')).to have_content 'invalid'
+ expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
+ end
+
+ it 'do not show "Edit" or full token for not owned trigger' do
+ # Create trigger with user different from current_user
+ create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
+
+ # See if trigger not owned by current_user shows only first few token chars and doesn't have copy-to-clipboard button
+ expect(page.find('.triggers-list')).to have_content(@project.triggers.first.token[0..3])
+ expect(page.find('.triggers-list')).not_to have_selector('button.btn-clipboard')
+
+ # See if trigger owner name doesn't match with current_user and trigger is non-editable
+ expect(page.find('.triggers-list .trigger-owner')).not_to have_content user.name
+ expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
+ end
+
+ it 'show "Edit" and full token for owned trigger' do
+ create(:ci_trigger, owner: user, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
+
+ # See if trigger shows full token and has copy-to-clipboard button
+ expect(page.find('.triggers-list')).to have_content @project.triggers.first.token
+ expect(page.find('.triggers-list')).to have_selector('button.btn-clipboard')
+
+ # See if trigger owner name matches with current_user and is editable
+ expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
+ expect(page.find('.triggers-list')).to have_selector('a[title="Edit"]')
+ end
+ end
end
end
diff --git a/spec/fixtures/api/schemas/current-board.json b/spec/fixtures/api/schemas/current-board.json
new file mode 100644
index 00000000000..2ddc038e908
--- /dev/null
+++ b/spec/fixtures/api/schemas/current-board.json
@@ -0,0 +1,16 @@
+{
+ "type": "object",
+ "allOf": [
+ { "$ref": "board.json" },
+ {
+ "required" : [
+ "id",
+ "name"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "name": { "type": "string" }
+ }
+ }
+ ]
+}
diff --git a/spec/frontend/boards/services/board_service_spec.js b/spec/frontend/boards/services/board_service_spec.js
index a8a322e7237..e106c2bf1f1 100644
--- a/spec/frontend/boards/services/board_service_spec.js
+++ b/spec/frontend/boards/services/board_service_spec.js
@@ -389,4 +389,163 @@ describe('BoardService', () => {
return expect(BoardService.toggleIssueSubscription(dummyEndpoint)).rejects.toThrow();
});
});
+
+ describe('allBoards', () => {
+ const url = `${endpoints.boardsEndpoint}.json`;
+
+ it('makes a request to fetch all boards', () => {
+ axiosMock.onGet(url).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.allBoards()).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onGet(url).replyOnce(500);
+
+ return expect(service.allBoards()).rejects.toThrow();
+ });
+ });
+
+ describe('recentBoards', () => {
+ const url = `${endpoints.recentBoardsEndpoint}.json`;
+
+ it('makes a request to fetch all boards', () => {
+ axiosMock.onGet(url).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.recentBoards()).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onGet(url).replyOnce(500);
+
+ return expect(service.recentBoards()).rejects.toThrow();
+ });
+ });
+
+ describe('createBoard', () => {
+ const labelIds = ['first label', 'second label'];
+ const assigneeId = 'as sign ee';
+ const milestoneId = 'vegetable soup';
+ const board = {
+ labels: labelIds.map(id => ({ id })),
+ assignee: { id: assigneeId },
+ milestone: { id: milestoneId },
+ };
+
+ describe('for existing board', () => {
+ const id = 'skate-board';
+ const url = `${endpoints.boardsEndpoint}/${id}.json`;
+ const expectedRequest = expect.objectContaining({
+ data: JSON.stringify({
+ board: {
+ ...board,
+ id,
+ label_ids: labelIds,
+ assignee_id: assigneeId,
+ milestone_id: milestoneId,
+ },
+ }),
+ });
+
+ let requestSpy;
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock.onPut(url).replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to update the board', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(
+ service.createBoard({
+ ...board,
+ id,
+ }),
+ )
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(
+ service.createBoard({
+ ...board,
+ id,
+ }),
+ )
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+ });
+
+ describe('for new board', () => {
+ const url = `${endpoints.boardsEndpoint}.json`;
+ const expectedRequest = expect.objectContaining({
+ data: JSON.stringify({
+ board: {
+ ...board,
+ label_ids: labelIds,
+ assignee_id: assigneeId,
+ milestone_id: milestoneId,
+ },
+ }),
+ });
+
+ let requestSpy;
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock.onPost(url).replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to create a new board', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.createBoard(board))
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(service.createBoard(board))
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+ });
+ });
+
+ describe('deleteBoard', () => {
+ const id = 'capsized';
+ const url = `${endpoints.boardsEndpoint}/${id}.json`;
+
+ it('makes a request to delete a boards', () => {
+ axiosMock.onDelete(url).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.deleteBoard({ id })).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onDelete(url).replyOnce(500);
+
+ return expect(service.deleteBoard({ id })).rejects.toThrow();
+ });
+ });
});
diff --git a/spec/frontend/create_merge_request_dropdown_spec.js b/spec/frontend/create_merge_request_dropdown_spec.js
index 6e41fdabdce..dcc6fa96d18 100644
--- a/spec/frontend/create_merge_request_dropdown_spec.js
+++ b/spec/frontend/create_merge_request_dropdown_spec.js
@@ -1,6 +1,7 @@
import axios from '~/lib/utils/axios_utils';
import MockAdapter from 'axios-mock-adapter';
import CreateMergeRequestDropdown from '~/create_merge_request_dropdown';
+import confidentialState from '~/confidential_merge_request/state';
import { TEST_HOST } from './helpers/test_constants';
describe('CreateMergeRequestDropdown', () => {
@@ -66,4 +67,37 @@ describe('CreateMergeRequestDropdown', () => {
);
});
});
+
+ describe('enable', () => {
+ beforeEach(() => {
+ dropdown.createMergeRequestButton.classList.add('disabled');
+ });
+
+ afterEach(() => {
+ confidentialState.selectedProject = {};
+ });
+
+ it('enables button when not confidential issue', () => {
+ dropdown.enable();
+
+ expect(dropdown.createMergeRequestButton.classList).not.toContain('disabled');
+ });
+
+ it('enables when can create confidential issue', () => {
+ document.querySelector('.js-create-mr').setAttribute('data-is-confidential', 'true');
+ confidentialState.selectedProject = { name: 'test' };
+
+ dropdown.enable();
+
+ expect(dropdown.createMergeRequestButton.classList).not.toContain('disabled');
+ });
+
+ it('does not enable when can not create confidential issue', () => {
+ document.querySelector('.js-create-mr').setAttribute('data-is-confidential', 'true');
+
+ dropdown.enable();
+
+ expect(dropdown.createMergeRequestButton.classList).toContain('disabled');
+ });
+ });
});
diff --git a/spec/frontend/repository/components/breadcrumbs_spec.js b/spec/frontend/repository/components/breadcrumbs_spec.js
index 068fa317a87..707eae34793 100644
--- a/spec/frontend/repository/components/breadcrumbs_spec.js
+++ b/spec/frontend/repository/components/breadcrumbs_spec.js
@@ -1,12 +1,14 @@
import { shallowMount, RouterLinkStub } from '@vue/test-utils';
+import { GlDropdown } from '@gitlab/ui';
import Breadcrumbs from '~/repository/components/breadcrumbs.vue';
let vm;
-function factory(currentPath) {
+function factory(currentPath, extraProps = {}) {
vm = shallowMount(Breadcrumbs, {
propsData: {
currentPath,
+ ...extraProps,
},
stubs: {
RouterLink: RouterLinkStub,
@@ -41,4 +43,20 @@ describe('Repository breadcrumbs component', () => {
.attributes('aria-current'),
).toEqual('page');
});
+
+ it('does not render add to tree dropdown when permissions are false', () => {
+ factory('/', { canCollaborate: false });
+
+ vm.setData({ userPermissions: { forkProject: false, createMergeRequestIn: false } });
+
+ expect(vm.find(GlDropdown).exists()).toBe(false);
+ });
+
+ it('renders add to tree dropdown when permissions are true', () => {
+ factory('/', { canCollaborate: true });
+
+ vm.setData({ userPermissions: { forkProject: true, createMergeRequestIn: true } });
+
+ expect(vm.find(GlDropdown).exists()).toBe(true);
+ });
});
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index aa0442ab847..94998d302f9 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -16,7 +16,7 @@ describe AvatarsHelper do
shared_examples 'resource with a custom avatar' do |source_type|
it 'returns a custom avatar image' do
expect(public_send("#{source_type}_icon", *helper_args))
- .to eq "<img src=\"#{resource.avatar.url}\" alt=\"Banana sample\" />"
+ .to eq "<img src=\"#{resource.avatar.url}\" />"
end
end
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 6808ed86c9a..1f236429347 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -29,14 +29,15 @@ describe BlobHelper do
let(:project) { create(:project, :repository, namespace: namespace) }
before do
- allow(self).to receive(:current_user).and_return(nil)
- allow(self).to receive(:can_collaborate_with_project?).and_return(true)
+ allow(helper).to receive(:current_user).and_return(nil)
+ allow(helper).to receive(:can?).and_return(true)
+ allow(helper).to receive(:can_collaborate_with_project?).and_return(true)
end
it 'verifies blob is text' do
expect(helper).not_to receive(:blob_text_viewable?)
- button = edit_blob_button(project, 'refs/heads/master', 'README.md')
+ button = helper.edit_blob_button(project, 'refs/heads/master', 'README.md')
expect(button).to start_with('<button')
end
@@ -46,25 +47,25 @@ describe BlobHelper do
expect(project.repository).not_to receive(:blob_at)
- edit_blob_button(project, 'refs/heads/master', 'README.md', blob: blob)
+ helper.edit_blob_button(project, 'refs/heads/master', 'README.md', blob: blob)
end
it 'returns a link with the proper route' do
stub_feature_flags(web_ide_default: false)
- link = edit_blob_button(project, 'master', 'README.md')
+ link = helper.edit_blob_button(project, 'master', 'README.md')
expect(Capybara.string(link).find_link('Edit')[:href]).to eq("/#{project.full_path}/edit/master/README.md")
end
it 'returns a link with a Web IDE route' do
- link = edit_blob_button(project, 'master', 'README.md')
+ link = helper.edit_blob_button(project, 'master', 'README.md')
expect(Capybara.string(link).find_link('Edit')[:href]).to eq("/-/ide/project/#{project.full_path}/edit/master/-/README.md")
end
it 'returns a link with the passed link_opts on the expected route' do
stub_feature_flags(web_ide_default: false)
- link = edit_blob_button(project, 'master', 'README.md', link_opts: { mr_id: 10 })
+ link = helper.edit_blob_button(project, 'master', 'README.md', link_opts: { mr_id: 10 })
expect(Capybara.string(link).find_link('Edit')[:href]).to eq("/#{project.full_path}/edit/master/README.md?mr_id=10")
end
@@ -203,6 +204,13 @@ describe BlobHelper do
describe '#ide_edit_path' do
let(:project) { create(:project) }
+ let(:current_user) { create(:user) }
+ let(:can_push_code) { true }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(current_user)
+ allow(helper).to receive(:can?).and_return(can_push_code)
+ end
around do |example|
old_script_name = Rails.application.routes.default_url_options[:script_name]
@@ -243,5 +251,21 @@ describe BlobHelper do
expect(helper.ide_edit_path(project, "testing/slashes", "readme.md/")).to eq("/-/ide/project/#{project.namespace.path}/#{project.path}/edit/testing/slashes/-/readme.md/")
end
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it 'returns IDE path inside the project' do
+ expect(helper.ide_edit_path(project, "master", "")).to eq("/-/ide/project/#{project.namespace.path}/#{project.path}/edit/master")
+ end
+ end
+
+ context 'when user cannot push to the project' do
+ let(:can_push_code) { false }
+
+ it "returns IDE path with the user's fork" do
+ expect(helper.ide_edit_path(project, "master", "")).to eq("/-/ide/project/#{current_user.namespace.full_path}/#{project.path}/edit/master")
+ end
+ end
end
end
diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb
index b22947911b9..f014537eb54 100644
--- a/spec/helpers/boards_helper_spec.rb
+++ b/spec/helpers/boards_helper_spec.rb
@@ -1,10 +1,12 @@
require 'spec_helper'
describe BoardsHelper do
+ set(:project) { create(:project) }
+
describe '#build_issue_link_base' do
context 'project board' do
it 'returns correct path for project board' do
- @project = create(:project)
+ @project = project
@board = create(:board, project: @project)
expect(build_issue_link_base).to eq("/#{@project.namespace.path}/#{@project.path}/issues")
@@ -31,7 +33,6 @@ describe BoardsHelper do
describe '#board_data' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
before do
@@ -46,4 +47,15 @@ describe BoardsHelper do
expect(helper.board_data[:lists_endpoint]).to eq(board_lists_path(board))
end
end
+
+ describe '#current_board_json' do
+ let(:board_json) { helper.current_board_json }
+
+ it 'can serialise with a basic set of attributes' do
+ board = create(:board, project: project)
+ assign(:board, board)
+
+ expect(board_json).to match_schema('current-board')
+ end
+ end
end
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index e6aacb5b92b..d25f0c6de4a 100644
--- a/spec/helpers/emails_helper_spec.rb
+++ b/spec/helpers/emails_helper_spec.rb
@@ -103,7 +103,7 @@ describe EmailsHelper do
appearance = create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png')
expect(header_logo).to eq(
- %{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />}
+ %{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" />}
)
end
end
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index 37e9ddadb8c..f92b94a9583 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -125,6 +125,14 @@ describe IconsHelper do
expect(file_type_icon_class('file', 0, 'filename.png')).to eq 'file-image-o'
end
+ it 'returns file-image-o class with .apng' do
+ expect(file_type_icon_class('file', 0, 'filename.apng')).to eq 'file-image-o'
+ end
+
+ it 'returns file-image-o class with .webp' do
+ expect(file_type_icon_class('file', 0, 'filename.webp')).to eq 'file-image-o'
+ end
+
it 'returns file-archive-o class with .tar' do
expect(file_type_icon_class('file', 0, 'filename.tar')).to eq 'file-archive-o'
end
@@ -145,6 +153,10 @@ describe IconsHelper do
expect(file_type_icon_class('file', 0, 'filename.MP3')).to eq 'file-audio-o'
end
+ it 'returns file-audio-o class with .m4a' do
+ expect(file_type_icon_class('file', 0, 'filename.m4a')).to eq 'file-audio-o'
+ end
+
it 'returns file-audio-o class with .wav' do
expect(file_type_icon_class('file', 0, 'filename.wav')).to eq 'file-audio-o'
end
@@ -161,6 +173,10 @@ describe IconsHelper do
expect(file_type_icon_class('file', 0, 'filename.mp4')).to eq 'file-video-o'
end
+ it 'returns file-word-o class with .odt' do
+ expect(file_type_icon_class('file', 0, 'filename.odt')).to eq 'file-word-o'
+ end
+
it 'returns file-word-o class with .doc' do
expect(file_type_icon_class('file', 0, 'filename.doc')).to eq 'file-word-o'
end
@@ -185,6 +201,10 @@ describe IconsHelper do
expect(file_type_icon_class('file', 0, 'filename.xlsx')).to eq 'file-excel-o'
end
+ it 'returns file-excel-o class with .odp' do
+ expect(file_type_icon_class('file', 0, 'filename.odp')).to eq 'file-powerpoint-o'
+ end
+
it 'returns file-excel-o class with .ppt' do
expect(file_type_icon_class('file', 0, 'filename.ppt')).to eq 'file-powerpoint-o'
end
diff --git a/spec/helpers/sorting_helper_spec.rb b/spec/helpers/sorting_helper_spec.rb
index f405268d198..5397a47b3dd 100644
--- a/spec/helpers/sorting_helper_spec.rb
+++ b/spec/helpers/sorting_helper_spec.rb
@@ -4,6 +4,11 @@ require 'spec_helper'
describe SortingHelper do
include ApplicationHelper
include IconsHelper
+ include ExploreHelper
+
+ def set_sorting_url(option)
+ allow(self).to receive(:request).and_return(double(path: 'http://test.com', query_parameters: { label_name: option }))
+ end
describe '#issuable_sort_option_title' do
it 'returns correct title for issuable_sort_option_overrides key' do
@@ -21,7 +26,7 @@ describe SortingHelper do
describe '#issuable_sort_direction_button' do
before do
- allow(self).to receive(:request).and_return(double(path: 'http://test.com', query_parameters: { label_name: 'test_label' }))
+ set_sorting_url 'test_label'
end
it 'keeps label filter param' do
@@ -44,4 +49,145 @@ describe SortingHelper do
expect(issuable_sort_direction_button('due_date')).to include('sort-lowest')
end
end
+
+ def stub_controller_path(value)
+ allow(helper.controller).to receive(:controller_path).and_return(value)
+ end
+
+ def project_common_options
+ {
+ sort_value_latest_activity => sort_title_latest_activity,
+ sort_value_recently_created => sort_title_created_date,
+ sort_value_name => sort_title_name,
+ sort_value_stars_desc => sort_title_stars
+ }
+ end
+
+ describe 'with `admin/projects` controller' do
+ before do
+ stub_controller_path 'admin/projects'
+ end
+
+ describe '#projects_sort_options_hash' do
+ it 'returns a hash of available sorting options' do
+ admin_options = project_common_options.merge({
+ sort_value_oldest_activity => sort_title_oldest_activity,
+ sort_value_oldest_created => sort_title_oldest_created,
+ sort_value_recently_created => sort_title_recently_created,
+ sort_value_stars_desc => sort_title_most_stars,
+ sort_value_largest_repo => sort_title_largest_repo
+ })
+
+ expect(projects_sort_options_hash).to eq(admin_options)
+ end
+ end
+ end
+
+ describe 'with `projects` controller' do
+ before do
+ stub_controller_path 'projects'
+ end
+
+ describe '#projects_sort_options_hash' do
+ it 'returns a hash of available sorting options' do
+ expect(projects_sort_options_hash).to include(project_common_options)
+ end
+ end
+
+ describe '#projects_reverse_sort_options_hash' do
+ context 'returns a reversed hash of available sorting options' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:sort_key, :reverse_sort_title) do
+ sort_value_latest_activity | sort_value_oldest_activity
+ sort_value_recently_created | sort_value_oldest_created
+ sort_value_name | sort_value_name_desc
+ sort_value_stars_desc | sort_value_stars_asc
+ sort_value_oldest_activity | sort_value_latest_activity
+ sort_value_oldest_created | sort_value_recently_created
+ sort_value_name_desc | sort_value_name
+ sort_value_stars_asc | sort_value_stars_desc
+ end
+
+ with_them do
+ it do
+ reverse_hash = projects_reverse_sort_options_hash
+
+ expect(reverse_hash).to include(sort_key)
+ expect(reverse_hash[sort_key]).to eq(reverse_sort_title)
+ end
+ end
+ end
+ end
+
+ describe '#project_sort_direction_button' do
+ context 'returns the correct icon for each sort option' do
+ using RSpec::Parameterized::TableSyntax
+
+ sort_lowest_icon = 'sort-lowest'
+ sort_highest_icon = 'sort-highest'
+
+ where(:selected_sort, :icon) do
+ sort_value_latest_activity | sort_highest_icon
+ sort_value_recently_created | sort_highest_icon
+ sort_value_name_desc | sort_highest_icon
+ sort_value_stars_desc | sort_highest_icon
+ sort_value_oldest_activity | sort_lowest_icon
+ sort_value_oldest_created | sort_lowest_icon
+ sort_value_name | sort_lowest_icon
+ sort_value_stars_asc | sort_lowest_icon
+ end
+
+ with_them do
+ it do
+ set_sorting_url selected_sort
+
+ expect(project_sort_direction_button(selected_sort)).to include(icon)
+ end
+ end
+ end
+
+ it 'returns the correct link to reverse the current sort option' do
+ sort_options_links = projects_reverse_sort_options_hash
+
+ sort_options_links.each do |selected_sort, reverse_sort|
+ set_sorting_url selected_sort
+
+ expect(project_sort_direction_button(selected_sort)).to include(reverse_sort)
+ end
+ end
+ end
+
+ describe '#projects_sort_option_titles' do
+ it 'returns a hash of titles for the sorting options' do
+ options = project_common_options.merge({
+ sort_value_oldest_activity => sort_title_latest_activity,
+ sort_value_oldest_created => sort_title_created_date,
+ sort_value_name_desc => sort_title_name,
+ sort_value_stars_asc => sort_title_stars
+ })
+
+ expect(projects_sort_option_titles).to eq(options)
+ end
+ end
+
+ describe 'with project_list_filter_bar off' do
+ before do
+ stub_feature_flags(project_list_filter_bar: false)
+ end
+
+ describe '#projects_sort_options_hash' do
+ it 'returns a hash of available sorting options' do
+ options = project_common_options.merge({
+ sort_value_oldest_activity => sort_title_oldest_activity,
+ sort_value_oldest_created => sort_title_oldest_created,
+ sort_value_recently_created => sort_title_recently_created,
+ sort_value_stars_desc => sort_title_most_stars
+ })
+
+ expect(projects_sort_options_hash).to eq(options)
+ end
+ end
+ end
+ end
end
diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb
index 25a2fcf5a81..2d276696208 100644
--- a/spec/helpers/visibility_level_helper_spec.rb
+++ b/spec/helpers/visibility_level_helper_spec.rb
@@ -137,32 +137,6 @@ describe VisibilityLevelHelper do
end
end
- describe "disallowed_visibility_level_description" do
- let(:group) { create(:group, :internal) }
- let!(:subgroup) { create(:group, :internal, parent: group) }
- let!(:project) { create(:project, :internal, group: group) }
-
- describe "project" do
- it "provides correct description for disabled levels" do
- expect(disallowed_visibility_level?(project, Gitlab::VisibilityLevel::PUBLIC)).to be_truthy
- expect(strip_tags disallowed_visibility_level_description(Gitlab::VisibilityLevel::PUBLIC, project))
- .to include "the visibility of #{project.group.name} is internal"
- end
- end
-
- describe "group" do
- it "provides correct description for disabled levels" do
- expect(disallowed_visibility_level?(group, Gitlab::VisibilityLevel::PRIVATE)).to be_truthy
- expect(disallowed_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, group))
- .to include "it contains projects with higher visibility", "it contains sub-groups with higher visibility"
-
- expect(disallowed_visibility_level?(subgroup, Gitlab::VisibilityLevel::PUBLIC)).to be_truthy
- expect(strip_tags disallowed_visibility_level_description(Gitlab::VisibilityLevel::PUBLIC, subgroup))
- .to include "the visibility of #{group.name} is internal"
- end
- end
- end
-
describe "selected_visibility_level" do
let(:group) { create(:group, :public) }
let!(:project) { create(:project, :internal, group: group) }
@@ -207,4 +181,50 @@ describe VisibilityLevelHelper do
end
end
end
+
+ describe 'multiple_visibility_levels_restricted?' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:user) { create(:user) }
+
+ subject { helper.multiple_visibility_levels_restricted? }
+
+ where(:restricted_visibility_levels, :expected) do
+ [Gitlab::VisibilityLevel::PUBLIC] | false
+ [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::INTERNAL] | true
+ [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE] | true
+ end
+
+ with_them do
+ before do
+ allow(helper).to receive(:current_user) { user }
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:restricted_visibility_levels) { restricted_visibility_levels }
+ end
+
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe 'all_visibility_levels_restricted?' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:user) { create(:user) }
+
+ subject { helper.all_visibility_levels_restricted? }
+
+ where(:restricted_visibility_levels, :expected) do
+ [Gitlab::VisibilityLevel::PUBLIC] | false
+ [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::INTERNAL] | false
+ Gitlab::VisibilityLevel.values | true
+ end
+
+ with_them do
+ before do
+ allow(helper).to receive(:current_user) { user }
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:restricted_visibility_levels) { restricted_visibility_levels }
+ end
+
+ it { is_expected.to eq(expected) }
+ end
+ end
end
diff --git a/spec/javascripts/boards/boards_store_spec.js b/spec/javascripts/boards/boards_store_spec.js
index 5266b1bdbfc..36bd7ada4f0 100644
--- a/spec/javascripts/boards/boards_store_spec.js
+++ b/spec/javascripts/boards/boards_store_spec.js
@@ -365,4 +365,17 @@ describe('Store', () => {
expect(boardsStore.timeTracking.limitToHours).toEqual(true);
});
});
+
+ describe('setCurrentBoard', () => {
+ const dummyBoard = 'hoverboard';
+
+ it('sets the current board', () => {
+ const { state } = boardsStore;
+ state.currentBoard = null;
+
+ boardsStore.setCurrentBoard(dummyBoard);
+
+ expect(state.currentBoard).toEqual(dummyBoard);
+ });
+ });
});
diff --git a/spec/javascripts/helpers/vuex_action_helper.js b/spec/javascripts/helpers/vuex_action_helper.js
index 88652202a8e..c5de31a4138 100644
--- a/spec/javascripts/helpers/vuex_action_helper.js
+++ b/spec/javascripts/helpers/vuex_action_helper.js
@@ -89,9 +89,7 @@ export default (
payload,
);
- return new Promise(resolve => {
- setImmediate(resolve);
- })
+ return new Promise(setImmediate)
.then(() => result)
.catch(error => {
validateResults();
diff --git a/spec/javascripts/registry/components/app_spec.js b/spec/javascripts/registry/components/app_spec.js
index 87237d2853d..7b9b8d2b039 100644
--- a/spec/javascripts/registry/components/app_spec.js
+++ b/spec/javascripts/registry/components/app_spec.js
@@ -90,7 +90,7 @@ describe('Registry List', () => {
.textContent.trim()
.replace(/[\r\n]+/g, ' '),
).toEqual(
- 'With the Container Registry, every project can have its own space to store its Docker images. Learn more about the Container Registry.',
+ 'With the Container Registry, every project can have its own space to store its Docker images. More Information',
);
done();
}, 0);
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 50741e249ca..ce453d7c483 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -3,6 +3,7 @@
*/
import $ from 'jquery';
+import 'core-js/features/set-immediate';
import 'vendor/jasmine-jquery';
import '~/commons';
import Vue from 'vue';
diff --git a/spec/lib/api/helpers/pagination_spec.rb b/spec/lib/api/helpers/pagination_spec.rb
index c788da55cd2..b0a00392957 100644
--- a/spec/lib/api/helpers/pagination_spec.rb
+++ b/spec/lib/api/helpers/pagination_spec.rb
@@ -114,7 +114,7 @@ describe API::Helpers::Pagination do
expect(paginated_relation.order_values).to be_present
expect(paginated_relation.order_values.size).to eq(1)
expect(paginated_relation.order_values.first).to be_descending
- expect(paginated_relation.order_values.first.expr.name).to eq :id
+ expect(paginated_relation.order_values.first.expr.name).to eq 'id'
end
end
@@ -151,9 +151,9 @@ describe API::Helpers::Pagination do
expect(paginated_relation.order_values).to be_present
expect(paginated_relation.order_values.size).to eq(2)
expect(paginated_relation.order_values.first).to be_descending
- expect(paginated_relation.order_values.first.expr.name).to eq :name
+ expect(paginated_relation.order_values.first.expr.name).to eq 'name'
expect(paginated_relation.order_values.second).to be_descending
- expect(paginated_relation.order_values.second.expr.name).to eq :id
+ expect(paginated_relation.order_values.second.expr.name).to eq 'id'
end
it 'returns the right records (first page)' do
@@ -341,7 +341,7 @@ describe API::Helpers::Pagination do
expect(resource.order_values).to be_empty
expect(paginated_relation.order_values).to be_present
expect(paginated_relation.order_values.first).to be_ascending
- expect(paginated_relation.order_values.first.expr.name).to eq :id
+ expect(paginated_relation.order_values.first.expr.name).to eq 'id'
end
it 'is present it does not add anything' do
@@ -349,7 +349,7 @@ describe API::Helpers::Pagination do
expect(paginated_relation.order_values).to be_present
expect(paginated_relation.order_values.first).to be_descending
- expect(paginated_relation.order_values.first.expr.name).to eq :created_at
+ expect(paginated_relation.order_values.first.expr.name).to eq 'created_at'
end
end
end
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb
index 919825a6102..e87440895e0 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::RedactorFilter do
+describe Banzai::Filter::ReferenceRedactorFilter do
include ActionView::Helpers::UrlHelper
include FilterSpecHelper
diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb
index 7b855251a74..e3e6e22568c 100644
--- a/spec/lib/banzai/object_renderer_spec.rb
+++ b/spec/lib/banzai/object_renderer_spec.rb
@@ -22,8 +22,8 @@ describe Banzai::ObjectRenderer do
expect(object.user_visible_reference_count).to eq 0
end
- it 'calls Banzai::Redactor to perform redaction' do
- expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
+ it 'calls Banzai::ReferenceRedactor to perform redaction' do
+ expect_any_instance_of(Banzai::ReferenceRedactor).to receive(:redact).and_call_original
renderer.render([object], :note)
end
@@ -82,8 +82,8 @@ describe Banzai::ObjectRenderer do
expect(cacheless_thing.redacted_title_html).to eq("Merge branch 'branch-merged' into 'master'")
end
- it 'calls Banzai::Redactor to perform redaction' do
- expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
+ it 'calls Banzai::ReferenceRedactor to perform redaction' do
+ expect_any_instance_of(Banzai::ReferenceRedactor).to receive(:redact).and_call_original
renderer.render([cacheless_thing], :title)
end
diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
index 7119c826bca..469692f7b5a 100644
--- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
@@ -32,7 +32,7 @@ describe Banzai::Pipeline::GfmPipeline do
result = described_class.call(markdown, project: project)[:output]
link = result.css('a').first
- expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12'
+ expect(link['href']).to eq 'http://issue-tracker.example.com/issues/12'
end
it 'parses cross-project references to regular issues' do
@@ -61,7 +61,7 @@ describe Banzai::Pipeline::GfmPipeline do
result = described_class.call(markdown, project: project)[:output]
link = result.css('a').first
- expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12'
+ expect(link['href']).to eq 'http://issue-tracker.example.com/issues/12'
end
it 'allows to use long external reference syntax for Redmine' do
@@ -70,7 +70,7 @@ describe Banzai::Pipeline::GfmPipeline do
result = described_class.call(markdown, project: project)[:output]
link = result.css('a').first
- expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12'
+ expect(link['href']).to eq 'http://issue-tracker.example.com/issues/12'
end
it 'parses cross-project references to regular issues' do
diff --git a/spec/lib/banzai/redactor_spec.rb b/spec/lib/banzai/reference_redactor_spec.rb
index 718649e0e10..a3b47c4d826 100644
--- a/spec/lib/banzai/redactor_spec.rb
+++ b/spec/lib/banzai/reference_redactor_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Redactor do
+describe Banzai::ReferenceRedactor do
let(:user) { create(:user) }
let(:project) { build(:project) }
let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) }
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 8f2434acd26..5293732ead1 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -45,28 +45,186 @@ module Gitlab
end
context "XSS" do
- links = {
- 'links' => {
+ items = {
+ 'link with extra attribute' => {
input: 'link:mylink"onmouseover="alert(1)[Click Here]',
output: "<div>\n<p><a href=\"mylink\">Click Here</a></p>\n</div>"
},
- 'images' => {
+ 'link with unsafe scheme' => {
+ input: 'link:data://danger[Click Here]',
+ output: "<div>\n<p><a>Click Here</a></p>\n</div>"
+ },
+ 'image with onerror' => {
input: 'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]',
output: "<div>\n<p><span><img src=\"https://localhost.com/image.png\" alt='Alt text\" onerror=\"alert(7)'></span></p>\n</div>"
},
- 'pre' => {
+ 'fenced code with inline script' => {
input: '```mypre"><script>alert(3)</script>',
output: "<div>\n<div>\n<pre class=\"code highlight js-syntax-highlight plaintext\" lang=\"plaintext\" v-pre=\"true\"><code><span id=\"LC1\" class=\"line\" lang=\"plaintext\">\"&gt;</span></code></pre>\n</div>\n</div>"
}
}
- links.each do |name, data|
+ items.each do |name, data|
it "does not convert dangerous #{name} into HTML" do
expect(render(data[:input], context)).to include(data[:output])
end
end
end
+ context 'with admonition' do
+ it 'preserves classes' do
+ input = <<~ADOC
+ NOTE: An admonition paragraph, like this note, grabs the reader’s attention.
+ ADOC
+
+ output = <<~HTML
+ <div class="admonitionblock">
+ <table>
+ <tr>
+ <td class="icon">
+ <i class="fa icon-note" title="Note"></i>
+ </td>
+ <td>
+ An admonition paragraph, like this note, grabs the reader’s attention.
+ </td>
+ </tr>
+ </table>
+ </div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
+ context 'with passthrough' do
+ it 'removes non heading ids' do
+ input = <<~ADOC
+ ++++
+ <h2 id="foo">Title</h2>
+ ++++
+ ADOC
+
+ output = <<~HTML
+ <h2>Title</h2>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
+ context 'with section anchors' do
+ it 'preserves ids and links' do
+ input = <<~ADOC
+ = Title
+
+ == First section
+
+ This is the first section.
+
+ == Second section
+
+ This is the second section.
+
+ == Thunder ⚡ !
+
+ This is the third section.
+ ADOC
+
+ output = <<~HTML
+ <h1>Title</h1>
+ <div>
+ <h2 id="user-content-first-section">
+ <a class="anchor" href="#user-content-first-section"></a>First section</h2>
+ <div>
+ <div>
+ <p>This is the first section.</p>
+ </div>
+ </div>
+ </div>
+ <div>
+ <h2 id="user-content-second-section">
+ <a class="anchor" href="#user-content-second-section"></a>Second section</h2>
+ <div>
+ <div>
+ <p>This is the second section.</p>
+ </div>
+ </div>
+ </div>
+ <div>
+ <h2 id="user-content-thunder">
+ <a class="anchor" href="#user-content-thunder"></a>Thunder ⚡ !</h2>
+ <div>
+ <div>
+ <p>This is the third section.</p>
+ </div>
+ </div>
+ </div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
+ context 'with checklist' do
+ it 'preserves classes' do
+ input = <<~ADOC
+ * [x] checked
+ * [ ] not checked
+ ADOC
+
+ output = <<~HTML
+ <div>
+ <ul class="checklist">
+ <li>
+ <p><i class="fa fa-check-square-o"></i> checked</p>
+ </li>
+ <li>
+ <p><i class="fa fa-square-o"></i> not checked</p>
+ </li>
+ </ul>
+ </div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
+ context 'with marks' do
+ it 'preserves classes' do
+ input = <<~ADOC
+ Werewolves are allergic to #cassia cinnamon#.
+
+ Did the werewolves read the [.small]#small print#?
+
+ Where did all the [.underline.small]#cores# run off to?
+
+ We need [.line-through]#ten# make that twenty VMs.
+
+ [.big]##O##nce upon an infinite loop.
+ ADOC
+
+ output = <<~HTML
+ <div>
+ <p>Werewolves are allergic to <mark>cassia cinnamon</mark>.</p>
+ </div>
+ <div>
+ <p>Did the werewolves read the <span class="small">small print</span>?</p>
+ </div>
+ <div>
+ <p>Where did all the <span class="underline small">cores</span> run off to?</p>
+ </div>
+ <div>
+ <p>We need <span class="line-through">ten</span> make that twenty VMs.</p>
+ </div>
+ <div>
+ <p><span class="big">O</span>nce upon an infinite loop.</p>
+ </div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
context 'with fenced block' do
it 'highlights syntax' do
input = <<~ADOC
diff --git a/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb b/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb
new file mode 100644
index 00000000000..5938ecca459
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::FixUserNamespaceNames, :migration, schema: 20190620112608 do
+ let(:namespaces) { table(:namespaces) }
+ let(:users) { table(:users) }
+ let(:user) { users.create(name: "The user's full name", projects_limit: 10, username: 'not-null', email: '1') }
+
+ context 'updating the namespace names' do
+ it 'updates a user namespace within range' do
+ user2 = users.create(name: "Other user's full name", projects_limit: 10, username: 'also-not-null', email: '2')
+ user_namespace1 = namespaces.create(
+ id: 2,
+ owner_id: user.id,
+ name: "Should be the user's name",
+ path: user.username
+ )
+ user_namespace2 = namespaces.create(
+ id: 3,
+ owner_id: user2.id,
+ name: "Should also be the user's name",
+ path: user.username
+ )
+
+ described_class.new.perform(1, 5)
+
+ expect(user_namespace1.reload.name).to eq("The user's full name")
+ expect(user_namespace2.reload.name).to eq("Other user's full name")
+ end
+
+ it 'does not update namespaces out of range' do
+ user_namespace = namespaces.create(
+ id: 6,
+ owner_id: user.id,
+ name: "Should be the user's name",
+ path: user.username
+ )
+
+ expect { described_class.new.perform(1, 5) }
+ .not_to change { user_namespace.reload.name }
+ end
+
+ it 'does not update groups owned by the users' do
+ user_group = namespaces.create(
+ id: 2,
+ owner_id: user.id,
+ name: 'A group name',
+ path: 'the-path',
+ type: 'Group'
+ )
+
+ expect { described_class.new.perform(1, 5) }
+ .not_to change { user_group.reload.name }
+ end
+ end
+
+ context 'namespace route names' do
+ let(:routes) { table(:routes) }
+ let(:namespace) do
+ namespaces.create(
+ id: 2,
+ owner_id: user.id,
+ name: "Will be updated to the user's name",
+ path: user.username
+ )
+ end
+
+ it "updates the route name if it didn't match the namespace" do
+ route = routes.create(path: namespace.path, name: 'Incorrect name', source_type: 'Namespace', source_id: namespace.id)
+
+ described_class.new.perform(1, 5)
+
+ expect(route.reload.name).to eq("The user's full name")
+ end
+
+ it 'updates the route name if it was nil match the namespace' do
+ route = routes.create(path: namespace.path, name: nil, source_type: 'Namespace', source_id: namespace.id)
+
+ described_class.new.perform(1, 5)
+
+ expect(route.reload.name).to eq("The user's full name")
+ end
+
+ it "doesn't update group routes" do
+ route = routes.create(path: 'group-path', name: 'Group name', source_type: 'Group', source_id: namespace.id)
+
+ expect { described_class.new.perform(1, 5) }
+ .not_to change { route.reload.name }
+ end
+
+ it "doesn't touch routes for namespaces out of range" do
+ user_namespace = namespaces.create(
+ id: 6,
+ owner_id: user.id,
+ name: "Should be the user's name",
+ path: user.username
+ )
+
+ expect { described_class.new.perform(1, 5) }
+ .not_to change { user_namespace.reload.name }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb b/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb
new file mode 100644
index 00000000000..d1d6d8411d1
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::FixUserProjectRouteNames, :migration, schema: 20190620112608 do
+ let(:namespaces) { table(:namespaces) }
+ let(:users) { table(:users) }
+ let(:routes) { table(:routes) }
+ let(:projects) { table(:projects) }
+
+ let(:user) { users.create(name: "The user's full name", projects_limit: 10, username: 'not-null', email: '1') }
+
+ let(:namespace) do
+ namespaces.create(
+ owner_id: user.id,
+ name: "Should eventually be the user's name",
+ path: user.username
+ )
+ end
+
+ let(:project) do
+ projects.create(namespace_id: namespace.id, name: 'Project Name')
+ end
+
+ it "updates the route for a project if it did not match the user's name" do
+ route = routes.create(
+ id: 1,
+ path: "#{user.username}/#{project.path}",
+ source_id: project.id,
+ source_type: 'Project',
+ name: 'Completely wrong'
+ )
+
+ described_class.new.perform(1, 5)
+
+ expect(route.reload.name).to eq("The user's full name / Project Name")
+ end
+
+ it 'updates the route for a project if the name was nil' do
+ route = routes.create(
+ id: 1,
+ path: "#{user.username}/#{project.path}",
+ source_id: project.id,
+ source_type: 'Project',
+ name: nil
+ )
+
+ described_class.new.perform(1, 5)
+
+ expect(route.reload.name).to eq("The user's full name / Project Name")
+ end
+
+ it 'does not update routes that were are out of the range' do
+ route = routes.create(
+ id: 6,
+ path: "#{user.username}/#{project.path}",
+ source_id: project.id,
+ source_type: 'Project',
+ name: 'Completely wrong'
+ )
+
+ expect { described_class.new.perform(1, 5) }
+ .not_to change { route.reload.name }
+ end
+
+ it 'does not update routes for projects in groups owned by the user' do
+ group = namespaces.create(
+ owner_id: user.id,
+ name: 'A group',
+ path: 'a-path',
+ type: ''
+ )
+ project = projects.create(namespace_id: group.id, name: 'Project Name')
+ route = routes.create(
+ id: 1,
+ path: "#{group.path}/#{project.path}",
+ source_id: project.id,
+ source_type: 'Project',
+ name: 'Completely wrong'
+ )
+
+ expect { described_class.new.perform(1, 5) }
+ .not_to change { route.reload.name }
+ end
+
+ it 'does not update routes for namespaces' do
+ route = routes.create(
+ id: 1,
+ path: namespace.path,
+ source_id: namespace.id,
+ source_type: 'Namespace',
+ name: 'Completely wrong'
+ )
+
+ expect { described_class.new.perform(1, 5) }
+ .not_to change { route.reload.name }
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb b/spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb
new file mode 100644
index 00000000000..c45c64f6a23
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_null_private_profile_to_false_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::MigrateNullPrivateProfileToFalse, :migration, schema: 20190620105427 do
+ let(:users) { table(:users) }
+
+ it 'correctly migrates nil private_profile to false' do
+ private_profile_true = users.create!(private_profile: true, projects_limit: 1, email: 'a@b.com')
+ private_profile_false = users.create!(private_profile: false, projects_limit: 1, email: 'b@c.com')
+ private_profile_nil = users.create!(private_profile: nil, projects_limit: 1, email: 'c@d.com')
+
+ described_class.new.perform(private_profile_true.id, private_profile_nil.id)
+
+ private_profile_true.reload
+ private_profile_false.reload
+ private_profile_nil.reload
+
+ expect(private_profile_true.private_profile).to eq(true)
+ expect(private_profile_false.private_profile).to eq(false)
+ expect(private_profile_nil.private_profile).to eq(false)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
index 4a81a37d341..ad4fa4fe03a 100644
--- a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
@@ -27,14 +27,19 @@ describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, :migra
merge_requests.create(params)
end
+ before do
+ create_merge_request(2, assignee_id: user.id)
+ create_merge_request(3, assignee_id: user_2.id)
+ create_merge_request(4, assignee_id: user_3.id)
+
+ # Test filtering MRs without assignees
+ create_merge_request(5, assignee_id: nil)
+ # Test filtering already migrated row
+ merge_request_assignees.create!(merge_request_id: 2, user_id: user_3.id)
+ end
+
describe '#perform' do
it 'creates merge_request_assignees rows according to merge_requests' do
- create_merge_request(2, assignee_id: user.id)
- create_merge_request(3, assignee_id: user_2.id)
- create_merge_request(4, assignee_id: user_3.id)
- # Test filtering already migrated row
- merge_request_assignees.create!(merge_request_id: 2, user_id: user_3.id)
-
subject.perform(1, 4)
rows = merge_request_assignees.order(:id).map { |row| row.attributes.slice('merge_request_id', 'user_id') }
@@ -53,4 +58,13 @@ describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, :migra
end
end
end
+
+ describe '#perform_all_sync' do
+ it 'executes peform for all merge requests in batches' do
+ expect(subject).to receive(:perform).with(2, 4).ordered
+ expect(subject).to receive(:perform).with(5, 5).ordered
+
+ subject.perform_all_sync(batch_size: 3)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
index 7d750877d09..b3e58c3dfdb 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
@@ -10,7 +10,11 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
- project: project, current_user: user, origin_ref: origin_ref, merge_request: merge_request)
+ project: project,
+ current_user: user,
+ origin_ref: origin_ref,
+ merge_request: merge_request,
+ trigger_request: trigger_request)
end
let(:step) { described_class.new(pipeline, command) }
@@ -18,6 +22,7 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
let(:ref) { 'master' }
let(:origin_ref) { ref }
let(:merge_request) { nil }
+ let(:trigger_request) { nil }
shared_context 'detached merge request pipeline' do
let(:merge_request) do
@@ -69,6 +74,43 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
end
end
+ context 'when pipeline triggered by legacy trigger' do
+ let(:user) { nil }
+ let(:trigger_request) do
+ build_stubbed(:ci_trigger_request, trigger: build_stubbed(:ci_trigger, owner: nil))
+ end
+
+ context 'when :use_legacy_pipeline_triggers feature flag is enabled' do
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: true)
+ step.perform!
+ end
+
+ it 'allows legacy triggers to create a pipeline' do
+ expect(pipeline).to be_valid
+ end
+
+ it 'does not break the chain' do
+ expect(step.break?).to eq false
+ end
+ end
+
+ context 'when :use_legacy_pipeline_triggers feature flag is disabled' do
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: false)
+ step.perform!
+ end
+
+ it 'prevents legacy triggers from creating a pipeline' do
+ expect(pipeline.errors.to_a).to include /Trigger token is invalid/
+ end
+
+ it 'breaks the pipeline builder chain' do
+ expect(step.break?).to eq true
+ end
+ end
+ end
+
describe '#allowed_to_create?' do
subject { step.allowed_to_create? }
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
index 30ea3f3e28e..6ce4b321397 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
@@ -107,42 +107,6 @@ describe Gitlab::Ci::Pipeline::Expression::Lexeme::Pattern do
expect(token.build.evaluate)
.to eq Gitlab::UntrustedRegexp.new('some numeric \$ pattern')
end
-
- context 'with the ci_variables_complex_expressions feature flag disabled' do
- before do
- stub_feature_flags(ci_variables_complex_expressions: false)
- end
-
- it 'is a greedy scanner for regexp boundaries' do
- scanner = StringScanner.new('/some .* / pattern/')
-
- token = described_class.scan(scanner)
-
- expect(token).not_to be_nil
- expect(token.build.evaluate)
- .to eq Gitlab::UntrustedRegexp.new('some .* / pattern')
- end
-
- it 'does not recognize the \ escape character for /' do
- scanner = StringScanner.new('/some .* \/ pattern/')
-
- token = described_class.scan(scanner)
-
- expect(token).not_to be_nil
- expect(token.build.evaluate)
- .to eq Gitlab::UntrustedRegexp.new('some .* \/ pattern')
- end
-
- it 'does not recognize the \ escape character for $' do
- scanner = StringScanner.new('/some numeric \$ pattern/')
-
- token = described_class.scan(scanner)
-
- expect(token).not_to be_nil
- expect(token.build.evaluate)
- .to eq Gitlab::UntrustedRegexp.new('some numeric \$ pattern')
- end
- end
end
describe '#evaluate' do
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
index d8db9c262a1..7c98e729b0b 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
@@ -80,34 +80,6 @@ describe Gitlab::Ci::Pipeline::Expression::Lexer do
it { is_expected.to eq(tokens) }
end
end
-
- context 'with the ci_variables_complex_expressions feature flag turned off' do
- before do
- stub_feature_flags(ci_variables_complex_expressions: false)
- end
-
- it 'incorrectly tokenizes conjunctive match statements as one match statement' do
- tokens = described_class.new('$PRESENT_VARIABLE =~ /my var/ && $EMPTY_VARIABLE =~ /nope/').tokens
-
- expect(tokens.map(&:value)).to eq(['$PRESENT_VARIABLE', '=~', '/my var/ && $EMPTY_VARIABLE =~ /nope/'])
- end
-
- it 'incorrectly tokenizes disjunctive match statements as one statement' do
- tokens = described_class.new('$PRESENT_VARIABLE =~ /my var/ || $EMPTY_VARIABLE =~ /nope/').tokens
-
- expect(tokens.map(&:value)).to eq(['$PRESENT_VARIABLE', '=~', '/my var/ || $EMPTY_VARIABLE =~ /nope/'])
- end
-
- it 'raises an error about && operators' do
- expect { described_class.new('$EMPTY_VARIABLE == "" && $PRESENT_VARIABLE').tokens }
- .to raise_error(Gitlab::Ci::Pipeline::Expression::Lexer::SyntaxError).with_message('Unknown lexeme found!')
- end
-
- it 'raises an error about || operators' do
- expect { described_class.new('$EMPTY_VARIABLE == "" || $PRESENT_VARIABLE').tokens }
- .to raise_error(Gitlab::Ci::Pipeline::Expression::Lexer::SyntaxError).with_message('Unknown lexeme found!')
- end
- end
end
describe '#lexemes' do
diff --git a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
index a2c2e3653d5..b259ef711aa 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
@@ -1,6 +1,4 @@
-# TODO switch this back after the "ci_variables_complex_expressions" feature flag is removed
-# require 'fast_spec_helper'
-require 'spec_helper'
+require 'fast_spec_helper'
require 'rspec-parameterized'
describe Gitlab::Ci::Pipeline::Expression::Statement do
@@ -118,54 +116,6 @@ describe Gitlab::Ci::Pipeline::Expression::Statement do
expect(subject.evaluate).to eq(value)
end
end
-
- context 'with the ci_variables_complex_expressions feature flag disabled' do
- before do
- stub_feature_flags(ci_variables_complex_expressions: false)
- end
-
- where(:expression, :value) do
- '$PRESENT_VARIABLE == "my variable"' | true
- '"my variable" == $PRESENT_VARIABLE' | true
- '$PRESENT_VARIABLE == null' | false
- '$EMPTY_VARIABLE == null' | false
- '"" == $EMPTY_VARIABLE' | true
- '$EMPTY_VARIABLE' | ''
- '$UNDEFINED_VARIABLE == null' | true
- 'null == $UNDEFINED_VARIABLE' | true
- '$PRESENT_VARIABLE' | 'my variable'
- '$UNDEFINED_VARIABLE' | nil
- "$PRESENT_VARIABLE =~ /var.*e$/" | true
- "$PRESENT_VARIABLE =~ /^var.*/" | false
- "$EMPTY_VARIABLE =~ /var.*/" | false
- "$UNDEFINED_VARIABLE =~ /var.*/" | false
- "$PRESENT_VARIABLE =~ /VAR.*/i" | true
- '$PATH_VARIABLE =~ /path/variable/' | true
- '$PATH_VARIABLE =~ /path\/variable/' | true
- '$FULL_PATH_VARIABLE =~ /^/a/full/path/variable/value$/' | true
- '$FULL_PATH_VARIABLE =~ /^\/a\/full\/path\/variable\/value$/' | true
- '$PRESENT_VARIABLE != "my variable"' | false
- '"my variable" != $PRESENT_VARIABLE' | false
- '$PRESENT_VARIABLE != null' | true
- '$EMPTY_VARIABLE != null' | true
- '"" != $EMPTY_VARIABLE' | false
- '$UNDEFINED_VARIABLE != null' | false
- 'null != $UNDEFINED_VARIABLE' | false
- "$PRESENT_VARIABLE !~ /var.*e$/" | false
- "$PRESENT_VARIABLE !~ /^var.*/" | true
- "$EMPTY_VARIABLE !~ /var.*/" | true
- "$UNDEFINED_VARIABLE !~ /var.*/" | true
- "$PRESENT_VARIABLE !~ /VAR.*/i" | false
- end
-
- with_them do
- let(:text) { expression }
-
- it "evaluates to `#{params[:value].inspect}`" do
- expect(subject.evaluate).to eq value
- end
- end
- end
end
describe '#truthful?' do
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index 909dbffa38f..db31e5280a3 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -80,7 +80,7 @@ describe Gitlab::CurrentSettings do
# during the initialization phase of the test suite, so instead let's mock the internals of it
expect(ActiveRecord::Base.connection).not_to receive(:active?)
expect(ActiveRecord::Base.connection).not_to receive(:cached_table_exists?)
- expect(ActiveRecord::Migrator).not_to receive(:needs_migration?)
+ expect_any_instance_of(ActiveRecord::MigrationContext).not_to receive(:needs_migration?)
expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0)
end
end
@@ -109,7 +109,7 @@ describe Gitlab::CurrentSettings do
context 'with pending migrations' do
before do
- expect(ActiveRecord::Migrator).to receive(:needs_migration?).and_return(true)
+ expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:needs_migration?).and_return(true)
end
shared_examples 'a non-persisted ApplicationSetting object' do
diff --git a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
index 48139c2f9dc..7833b9f387d 100644
--- a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
@@ -105,6 +105,7 @@ describe Gitlab::Email::Handler::CreateIssueHandler do
context "when the issue could not be saved" do
before do
allow_any_instance_of(Issue).to receive(:persisted?).and_return(false)
+ allow_any_instance_of(Issue).to receive(:ensure_metrics).and_return(nil)
end
it "raises an InvalidIssueError" do
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index eed233f1f3e..b8debee3b58 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -171,17 +171,6 @@ describe Gitlab::GitalyClient do
end
end
end
-
- context 'when catfile-cache feature is disabled' do
- before do
- stub_feature_flags({ 'gitaly_catfile-cache': false })
- end
-
- it 'does not set the gitaly-session-id in the metadata' do
- results = described_class.request_kwargs('default', nil)
- expect(results[:metadata]).not_to include('gitaly-session-id')
- end
- end
end
describe 'enforce_gitaly_request_limits?' do
diff --git a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
index 99669285d5b..873728f9909 100644
--- a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
+++ b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
@@ -22,7 +22,9 @@ describe Gitlab::ImportExport::AttributeCleaner do
'some_html' => '<p>dodgy html</p>',
'legit_html' => '<p>legit html</p>',
'_html' => '<p>perfectly ordinary html</p>',
- 'cached_markdown_version' => 12345
+ 'cached_markdown_version' => 12345,
+ 'group_id' => 99,
+ 'commit_id' => 99
}
end
@@ -31,7 +33,9 @@ describe Gitlab::ImportExport::AttributeCleaner do
'project_id' => 99,
'user_id' => 99,
'random_id_in_the_middle' => 99,
- 'notid' => 99
+ 'notid' => 99,
+ 'group_id' => 99,
+ 'commit_id' => 99
}
end
@@ -59,6 +63,6 @@ describe Gitlab::ImportExport::AttributeCleaner do
it 'does not remove excluded key if not listed' do
parsed_hash = described_class.clean(relation_hash: unsafe_hash, relation_class: relation_class)
- expect(parsed_hash.keys).to eq post_safe_hash.keys + excluded_keys
+ expect(parsed_hash.keys).to match_array post_safe_hash.keys + excluded_keys
end
end
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 8be074f4b9b..c0b97486eeb 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -6630,8 +6630,16 @@
"id": 123,
"token": "cdbfasdf44a5958c83654733449e585",
"project_id": 5,
+ "owner_id": 1,
"created_at": "2017-01-16T15:25:28.637Z",
"updated_at": "2017-01-16T15:25:28.637Z"
+ },
+ {
+ "id": 456,
+ "token": "33a66349b5ad01fc00174af87804e40",
+ "project_id": 5,
+ "created_at": "2017-01-16T15:25:29.637Z",
+ "updated_at": "2017-01-16T15:25:29.637Z"
}
],
"deploy_keys": [],
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index ca46006ea58..e6ce3f1bcea 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -32,6 +32,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
context 'JSON' do
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: false)
+ end
+
it 'restores models based on JSON' do
expect(@restored_project_json).to be_truthy
end
@@ -198,8 +202,9 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
context 'tokens are regenerated' do
- it 'has a new CI trigger token' do
- expect(Ci::Trigger.where(token: 'cdbfasdf44a5958c83654733449e585')).to be_empty
+ it 'has new CI trigger tokens' do
+ expect(Ci::Trigger.where(token: %w[cdbfasdf44a5958c83654733449e585 33a66349b5ad01fc00174af87804e40]))
+ .to be_empty
end
it 'has a new CI build token' do
@@ -212,7 +217,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
expect(@project.merge_requests.size).to eq(9)
end
- it 'has the correct number of triggers' do
+ it 'only restores valid triggers' do
expect(@project.triggers.size).to eq(1)
end
diff --git a/spec/lib/gitlab/kubernetes/helm/delete_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/delete_command_spec.rb
index cae92305b19..39a46f9bc6d 100644
--- a/spec/lib/gitlab/kubernetes/helm/delete_command_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/delete_command_spec.rb
@@ -20,6 +20,15 @@ describe Gitlab::Kubernetes::Helm::DeleteCommand do
end
end
+ let(:tls_flags) do
+ <<~EOS.squish
+ --tls
+ --tls-ca-cert /data/helm/app-name/config/ca.pem
+ --tls-cert /data/helm/app-name/config/cert.pem
+ --tls-key /data/helm/app-name/config/key.pem
+ EOS
+ end
+
context 'when there is a ca.pem file' do
let(:files) { { 'ca.pem': 'some file content' } }
@@ -27,7 +36,7 @@ describe Gitlab::Kubernetes::Helm::DeleteCommand do
let(:commands) do
<<~EOS
helm init --upgrade
- for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done
+ for i in $(seq 1 30); do helm version #{tls_flags} && break; sleep 1s; echo "Retrying ($i)..."; done
#{helm_delete_command}
EOS
end
@@ -35,10 +44,7 @@ describe Gitlab::Kubernetes::Helm::DeleteCommand do
let(:helm_delete_command) do
<<~EOS.squish
helm delete --purge app-name
- --tls
- --tls-ca-cert /data/helm/app-name/config/ca.pem
- --tls-cert /data/helm/app-name/config/cert.pem
- --tls-key /data/helm/app-name/config/key.pem
+ #{tls_flags}
EOS
end
end
diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
index db76d5d207e..7395b095454 100644
--- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
@@ -36,7 +36,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
let(:commands) do
<<~EOS
helm init --upgrade
- for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done
+ for i in $(seq 1 30); do helm version #{tls_flags} && break; sleep 1s; echo "Retrying ($i)..."; done
helm repo add app-name https://repository.example.com
helm repo update
#{helm_install_comand}
@@ -64,7 +64,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
let(:commands) do
<<~EOS
helm init --upgrade
- for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done
+ for i in $(seq 1 30); do helm version #{tls_flags} && break; sleep 1s; echo "Retrying ($i)..."; done
helm repo add app-name https://repository.example.com
helm repo update
#{helm_install_command}
@@ -93,7 +93,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
let(:commands) do
<<~EOS
helm init --upgrade
- for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done
+ for i in $(seq 1 30); do helm version #{tls_flags} && break; sleep 1s; echo "Retrying ($i)..."; done
#{helm_install_command}
EOS
end
@@ -120,7 +120,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
let(:commands) do
<<~EOS
helm init --upgrade
- for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done
+ for i in $(seq 1 30); do helm version #{tls_flags} && break; sleep 1s; echo "Retrying ($i)..."; done
helm repo add app-name https://repository.example.com
helm repo update
/bin/date
@@ -151,7 +151,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
let(:commands) do
<<~EOS
helm init --upgrade
- for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done
+ for i in $(seq 1 30); do helm version #{tls_flags} && break; sleep 1s; echo "Retrying ($i)..."; done
helm repo add app-name https://repository.example.com
helm repo update
#{helm_install_command}
@@ -210,7 +210,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
let(:commands) do
<<~EOS
helm init --upgrade
- for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done
+ for i in $(seq 1 30); do helm version #{tls_flags} && break; sleep 1s; echo "Retrying ($i)..."; done
helm repo add app-name https://repository.example.com
helm repo update
#{helm_install_command}
diff --git a/spec/lib/gitlab/lets_encrypt_spec.rb b/spec/lib/gitlab/lets_encrypt_spec.rb
index 674b114e9d3..65aea0937f1 100644
--- a/spec/lib/gitlab/lets_encrypt_spec.rb
+++ b/spec/lib/gitlab/lets_encrypt_spec.rb
@@ -10,21 +10,10 @@ describe ::Gitlab::LetsEncrypt do
end
describe '.enabled?' do
- let(:project) { create(:project) }
- let(:pages_domain) { create(:pages_domain, project: project) }
-
- subject { described_class.enabled?(pages_domain) }
+ subject { described_class.enabled? }
context 'when terms of service are accepted' do
it { is_expected.to eq(true) }
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(pages_auto_ssl: false)
- end
-
- it { is_expected.to eq(false) }
- end
end
context 'when terms of service are not accepted' do
@@ -34,23 +23,5 @@ describe ::Gitlab::LetsEncrypt do
it { is_expected.to eq(false) }
end
-
- context 'when feature flag for project is disabled' do
- before do
- stub_feature_flags(pages_auto_ssl_for_project: false)
- end
-
- it 'returns false' do
- is_expected.to eq(false)
- end
- end
-
- context 'when domain has not project' do
- let(:pages_domain) { create(:pages_domain) }
-
- it 'returns false' do
- is_expected.to eq(false)
- end
- end
end
end
diff --git a/spec/lib/gitlab/omniauth_initializer_spec.rb b/spec/lib/gitlab/omniauth_initializer_spec.rb
index f9c0daf1ef1..ef5c93e5c6b 100644
--- a/spec/lib/gitlab/omniauth_initializer_spec.rb
+++ b/spec/lib/gitlab/omniauth_initializer_spec.rb
@@ -83,5 +83,33 @@ describe Gitlab::OmniauthInitializer do
subject.execute([cas3_config])
end
+
+ it 'converts client_auth_method to a Symbol for openid_connect' do
+ openid_connect_config = {
+ 'name' => 'openid_connect',
+ 'args' => { name: 'openid_connect', client_auth_method: 'basic' }
+ }
+
+ expect(devise_config).to receive(:omniauth).with(
+ :openid_connect,
+ { name: 'openid_connect', client_auth_method: :basic }
+ )
+
+ subject.execute([openid_connect_config])
+ end
+
+ it 'converts client_auth_method to a Symbol for strategy_class OpenIDConnect' do
+ openid_connect_config = {
+ 'name' => 'openid_connect',
+ 'args' => { strategy_class: OmniAuth::Strategies::OpenIDConnect, client_auth_method: 'jwt_bearer' }
+ }
+
+ expect(devise_config).to receive(:omniauth).with(
+ :openid_connect,
+ { strategy_class: OmniAuth::Strategies::OpenIDConnect, client_auth_method: :jwt_bearer }
+ )
+
+ subject.execute([openid_connect_config])
+ end
end
end
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index 253366e0789..f8b0cbfb6f6 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -353,7 +353,7 @@ describe Gitlab::UrlBlocker do
end
end
- describe '#validate_hostname!' do
+ describe '#validate_hostname' do
let(:ip_addresses) do
[
'2001:db8:1f70::999:de8:7648:6e8',
@@ -378,7 +378,7 @@ describe Gitlab::UrlBlocker do
it 'does not raise error for valid Ip addresses' do
ip_addresses.each do |ip|
- expect { described_class.send(:validate_hostname!, ip) }.not_to raise_error
+ expect { described_class.send(:validate_hostname, ip) }.not_to raise_error
end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb
new file mode 100644
index 00000000000..38b4c22e186
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::UsageDataCounters::RedisCounter, :clean_gitlab_redis_shared_state do
+ context 'when redis_key is not defined' do
+ subject do
+ Class.new.extend(described_class)
+ end
+
+ describe '.increment' do
+ it 'raises a NotImplementedError exception' do
+ expect { subject.increment}.to raise_error(NotImplementedError)
+ end
+ end
+
+ describe '.total_count' do
+ it 'raises a NotImplementedError exception' do
+ expect { subject.total_count}.to raise_error(NotImplementedError)
+ end
+ end
+ end
+
+ context 'when redis_key is defined' do
+ subject do
+ counter_module = described_class
+
+ Class.new do
+ extend counter_module
+
+ def self.redis_counter_key
+ 'foo_redis_key'
+ end
+ end
+ end
+
+ describe '.increment' do
+ it 'increments the web ide commits counter by 1' do
+ expect do
+ subject.increment
+ end.to change { subject.total_count }.from(0).to(1)
+ end
+ end
+
+ describe '.total_count' do
+ it 'returns the total amount of web ide commits' do
+ subject.increment
+ subject.increment
+
+ expect(subject.total_count).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 67d49a30825..90a534de202 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::UsageData do
before do
create(:jira_service, project: projects[0])
create(:jira_service, project: projects[1])
- create(:jira_cloud_service, project: projects[2])
+ create(:jira_service, :jira_cloud_service, project: projects[2])
create(:prometheus_service, project: projects[1])
create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true)
create(:service, project: projects[1], type: 'SlackService', active: true)
diff --git a/spec/lib/gitlab/web_ide_commits_counter_spec.rb b/spec/lib/gitlab/web_ide_commits_counter_spec.rb
deleted file mode 100644
index c51889a1c63..00000000000
--- a/spec/lib/gitlab/web_ide_commits_counter_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe Gitlab::WebIdeCommitsCounter, :clean_gitlab_redis_shared_state do
- describe '.increment' do
- it 'increments the web ide commits counter by 1' do
- expect do
- described_class.increment
- end.to change { described_class.total_count }.from(0).to(1)
- end
- end
-
- describe '.total_count' do
- it 'returns the total amount of web ide commits' do
- expect(described_class.total_count).to eq(0)
- end
- end
-end
diff --git a/spec/mailers/emails/pages_domains_spec.rb b/spec/mailers/emails/pages_domains_spec.rb
index eae83cd64d3..c52e3c2191d 100644
--- a/spec/mailers/emails/pages_domains_spec.rb
+++ b/spec/mailers/emails/pages_domains_spec.rb
@@ -23,7 +23,7 @@ describe Emails::PagesDomains do
is_expected.to have_body_text(domain.domain)
is_expected.to have_body_text domain.url
is_expected.to have_body_text project_pages_domain_url(project, domain)
- is_expected.to have_body_text help_page_url('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
+ is_expected.to have_body_text help_page_url('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: link_anchor)
end
end
end
@@ -50,6 +50,7 @@ describe Emails::PagesDomains do
describe '#pages_domain_enabled_email' do
let(:email_subject) { "#{project.path} | GitLab Pages domain '#{domain.domain}' has been enabled" }
+ let(:link_anchor) { 'steps' }
subject { Notify.pages_domain_enabled_email(domain, user) }
@@ -60,6 +61,7 @@ describe Emails::PagesDomains do
describe '#pages_domain_disabled_email' do
let(:email_subject) { "#{project.path} | GitLab Pages domain '#{domain.domain}' has been disabled" }
+ let(:link_anchor) { '4-verify-the-domains-ownership' }
subject { Notify.pages_domain_disabled_email(domain, user) }
@@ -72,6 +74,7 @@ describe Emails::PagesDomains do
describe '#pages_domain_verification_succeeded_email' do
let(:email_subject) { "#{project.path} | Verification succeeded for GitLab Pages domain '#{domain.domain}'" }
+ let(:link_anchor) { 'steps' }
subject { Notify.pages_domain_verification_succeeded_email(domain, user) }
@@ -82,6 +85,7 @@ describe Emails::PagesDomains do
describe '#pages_domain_verification_failed_email' do
let(:email_subject) { "#{project.path} | ACTION REQUIRED: Verification failed for GitLab Pages domain '#{domain.domain}'" }
+ let(:link_anchor) { 'steps' }
subject { Notify.pages_domain_verification_failed_email(domain, user) }
diff --git a/spec/migrations/active_record/schema_spec.rb b/spec/migrations/active_record/schema_spec.rb
index fbf5d387d0e..bc246f88685 100644
--- a/spec/migrations/active_record/schema_spec.rb
+++ b/spec/migrations/active_record/schema_spec.rb
@@ -15,7 +15,7 @@ describe ActiveRecord::Schema do
it '> schema version equals last migration timestamp' do
defined_schema_version = File.open(Rails.root.join('db', 'schema.rb')) do |file|
file.find { |line| line =~ /ActiveRecord::Schema.define/ }
- end.match(/(\d+)/)[0].to_i
+ end.match(/(\d{4}_\d{2}_\d{2}_\d{6})/)[0].to_i
expect(defined_schema_version).to eq(latest_migration_timestamp)
end
diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb
index fde8375f2a5..5b5d6f51b33 100644
--- a/spec/models/ci/trigger_spec.rb
+++ b/spec/models/ci/trigger_spec.rb
@@ -54,19 +54,31 @@ describe Ci::Trigger do
end
describe '#can_access_project?' do
+ let(:owner) { create(:user) }
let(:trigger) { create(:ci_trigger, owner: owner, project: project) }
context 'when owner is blank' do
- let(:owner) { nil }
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: false)
+ trigger.update_attribute(:owner, nil)
+ end
subject { trigger.can_access_project? }
- it { is_expected.to eq(true) }
+ it { is_expected.to eq(false) }
+
+ context 'when :use_legacy_pipeline_triggers feature flag is enabled' do
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: true)
+ end
+
+ subject { trigger.can_access_project? }
+
+ it { is_expected.to eq(true) }
+ end
end
context 'when owner is set' do
- let(:owner) { create(:user) }
-
subject { trigger.can_access_project? }
context 'and is member of the project' do
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index 4f0cd0efe9c..4abe45a2152 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -18,7 +18,7 @@ describe Clusters::Applications::Runner do
subject { gitlab_runner.can_uninstall? }
- it { is_expected.to be_falsey }
+ it { is_expected.to be_truthy }
end
describe '#install_command' do
@@ -156,4 +156,35 @@ describe Clusters::Applications::Runner do
end
end
end
+
+ describe '#prepare_uninstall' do
+ it 'pauses associated runner' do
+ active_runner = create(:ci_runner, contacted_at: 1.second.ago)
+
+ expect(active_runner.status).to eq(:online)
+
+ application_runner = create(:clusters_applications_runner, :scheduled, runner: active_runner)
+ application_runner.prepare_uninstall
+
+ expect(active_runner.status).to eq(:paused)
+ end
+ end
+
+ describe '#make_uninstalling!' do
+ subject { create(:clusters_applications_runner, :scheduled, runner: ci_runner) }
+
+ it 'calls prepare_uninstall' do
+ expect_any_instance_of(described_class).to receive(:prepare_uninstall).and_call_original
+
+ subject.make_uninstalling!
+ end
+ end
+
+ describe '#post_uninstall' do
+ it 'destroys its runner' do
+ application_runner = create(:clusters_applications_runner, :scheduled, runner: ci_runner)
+
+ expect { application_runner.post_uninstall }.to change { Ci::Runner.count }.by(-1)
+ end
+ end
end
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index 1fb0dd5030c..31163a5bb5c 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -15,23 +15,46 @@ describe Group, 'Routable' do
end
describe 'Callbacks' do
- it 'creates route record on create' do
- expect(group.route.path).to eq(group.path)
- expect(group.route.name).to eq(group.name)
- end
+ context 'for a group' do
+ it 'creates route record on create' do
+ expect(group.route.path).to eq(group.path)
+ expect(group.route.name).to eq(group.name)
+ end
+
+ it 'updates route record on path change' do
+ group.update(path: 'wow', name: 'much')
- it 'updates route record on path change' do
- group.update(path: 'wow', name: 'much')
+ expect(group.route.path).to eq('wow')
+ expect(group.route.name).to eq('much')
+ end
+
+ it 'ensure route path uniqueness across different objects' do
+ create(:group, parent: group, path: 'xyz')
+ duplicate = build(:project, namespace: group, path: 'xyz')
- expect(group.route.path).to eq('wow')
- expect(group.route.name).to eq('much')
+ expect { duplicate.save! }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Path has already been taken')
+ end
end
- it 'ensure route path uniqueness across different objects' do
- create(:group, parent: group, path: 'xyz')
- duplicate = build(:project, namespace: group, path: 'xyz')
+ context 'for a user' do
+ let(:user) { create(:user, username: 'jane', name: "Jane Doe") }
- expect { duplicate.save! }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Path has already been taken')
+ it 'creates the route for a record on create' do
+ expect(user.namespace.name).to eq('Jane Doe')
+ expect(user.namespace.path).to eq('jane')
+ end
+
+ it 'updates routes and nested routes on name change' do
+ project = create(:project, path: 'work-stuff', name: 'Work stuff', namespace: user.namespace)
+
+ user.update!(username: 'jaen', name: 'Jaen Did')
+ project.reload
+
+ expect(user.namespace.name).to eq('Jaen Did')
+ expect(user.namespace.path).to eq('jaen')
+ expect(project.full_name).to eq('Jaen Did / Work stuff')
+ expect(project.full_path).to eq('jaen/work-stuff')
+ end
end
end
diff --git a/spec/models/concerns/stepable_spec.rb b/spec/models/concerns/stepable_spec.rb
new file mode 100644
index 00000000000..5685de6a9bf
--- /dev/null
+++ b/spec/models/concerns/stepable_spec.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Stepable do
+ let(:described_class) do
+ Class.new do
+ include Stepable
+
+ steps :method1, :method2, :method3
+
+ def execute
+ execute_steps
+ end
+
+ private
+
+ def method1
+ { status: :success }
+ end
+
+ def method2
+ return { status: :error } unless @pass
+
+ { status: :success, variable1: 'var1' }
+ end
+
+ def method3
+ { status: :success, variable2: 'var2' }
+ end
+ end
+ end
+
+ let(:prepended_module) do
+ Module.new do
+ extend ActiveSupport::Concern
+
+ prepended do
+ steps :appended_method1
+ end
+
+ private
+
+ def appended_method1
+ { status: :success }
+ end
+ end
+ end
+
+ before do
+ described_class.prepend(prepended_module)
+ end
+
+ it 'stops after the first error' do
+ expect(subject).not_to receive(:method3)
+ expect(subject).not_to receive(:appended_method1)
+
+ expect(subject.execute).to eq(
+ status: :error,
+ failed_step: :method2
+ )
+ end
+
+ context 'when all methods return success' do
+ before do
+ subject.instance_variable_set(:@pass, true)
+ end
+
+ it 'calls all methods in order' do
+ expect(subject).to receive(:method1).and_call_original.ordered
+ expect(subject).to receive(:method2).and_call_original.ordered
+ expect(subject).to receive(:method3).and_call_original.ordered
+ expect(subject).to receive(:appended_method1).and_call_original.ordered
+
+ subject.execute
+ end
+
+ it 'merges variables returned by all steps' do
+ expect(subject.execute).to eq(
+ status: :success,
+ variable1: 'var1',
+ variable2: 'var2'
+ )
+ end
+ end
+
+ context 'with multiple stepable classes' do
+ let(:other_class) do
+ Class.new do
+ include Stepable
+
+ steps :other_method1, :other_method2
+
+ private
+
+ def other_method1
+ { status: :success }
+ end
+
+ def other_method2
+ { status: :success }
+ end
+ end
+ end
+
+ it 'does not leak steps' do
+ expect(other_class.new.steps).to contain_exactly(:other_method1, :other_method2)
+ expect(subject.steps).to contain_exactly(:method1, :method2, :method3, :appended_method1)
+ end
+ end
+end
diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb
index 7b18e24a351..4ccbdf29df6 100644
--- a/spec/models/cycle_analytics/issue_spec.rb
+++ b/spec/models/cycle_analytics/issue_spec.rb
@@ -24,7 +24,7 @@ describe 'CycleAnalytics#issue' do
["list label added to issue",
-> (context, data) do
if data[:issue].persisted?
- data[:issue].update(label_ids: [context.create(:label, lists: [context.create(:list)]).id])
+ data[:issue].update(label_ids: [context.create(:list).label_id])
end
end]],
post_fn: -> (context, data) do
diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb
index 73fc98ba6cf..c99c38e9cf3 100644
--- a/spec/models/cycle_analytics/plan_spec.rb
+++ b/spec/models/cycle_analytics/plan_spec.rb
@@ -25,7 +25,7 @@ describe 'CycleAnalytics#plan' do
end],
["list label added to issue",
-> (context, data) do
- data[:issue].update(label_ids: [context.create(:label, lists: [context.create(:list)]).id])
+ data[:issue].update(label_ids: [context.create(:list).label_id])
end]],
end_time_conditions: [["issue mentioned in a commit",
-> (context, data) do
diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb
index 07858fe8a70..7aa0d97b194 100644
--- a/spec/models/issue/metrics_spec.rb
+++ b/spec/models/issue/metrics_spec.rb
@@ -32,7 +32,7 @@ describe Issue::Metrics do
context "list labels" do
it "records the first time an issue is associated with a list label" do
- list_label = create(:label, lists: [create(:list)])
+ list_label = create(:list).label
time = Time.now
Timecop.freeze(time) { subject.update(label_ids: [list_label.id]) }
metrics = subject.metrics
@@ -43,9 +43,9 @@ describe Issue::Metrics do
it "does not record the second time an issue is associated with a list label" do
time = Time.now
- first_list_label = create(:label, lists: [create(:list)])
+ first_list_label = create(:list).label
Timecop.freeze(time) { subject.update(label_ids: [first_list_label.id]) }
- second_list_label = create(:label, lists: [create(:list)])
+ second_list_label = create(:list).label
Timecop.freeze(time + 5.hours) { subject.update(label_ids: [second_list_label.id]) }
metrics = subject.metrics
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 9b0c232f370..6a5bd276233 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -2454,6 +2454,13 @@ describe MergeRequest do
describe "#diff_refs" do
context "with diffs" do
subject { create(:merge_request, :with_diffs) }
+ let(:expected_diff_refs) do
+ Gitlab::Diff::DiffRefs.new(
+ base_sha: subject.merge_request_diff.base_commit_sha,
+ start_sha: subject.merge_request_diff.start_commit_sha,
+ head_sha: subject.merge_request_diff.head_commit_sha
+ )
+ end
it "does not touch the repository" do
subject # Instantiate the object
@@ -2464,14 +2471,18 @@ describe MergeRequest do
end
it "returns expected diff_refs" do
- expected_diff_refs = Gitlab::Diff::DiffRefs.new(
- base_sha: subject.merge_request_diff.base_commit_sha,
- start_sha: subject.merge_request_diff.start_commit_sha,
- head_sha: subject.merge_request_diff.head_commit_sha
- )
-
expect(subject.diff_refs).to eq(expected_diff_refs)
end
+
+ context 'when importing' do
+ before do
+ subject.importing = true
+ end
+
+ it "returns MR diff_refs" do
+ expect(subject.diff_refs).to eq(expected_diff_refs)
+ end
+ end
end
end
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index 661957cf08b..973c67937b7 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -53,24 +53,33 @@ describe PagesDomain do
end
let(:pages_domain) do
- build(:pages_domain, certificate: certificate, key: key).tap do |pd|
+ build(:pages_domain, certificate: certificate, key: key,
+ auto_ssl_enabled: auto_ssl_enabled).tap do |pd|
allow(pd).to receive(:project).and_return(project)
pd.valid?
end
end
- where(:pages_https_only, :certificate, :key, :errors_on) do
+ where(:pages_https_only, :certificate, :key, :auto_ssl_enabled, :errors_on) do
attributes = attributes_for(:pages_domain)
cert, key = attributes.fetch_values(:certificate, :key)
- true | nil | nil | %i(certificate key)
- true | cert | nil | %i(key)
- true | nil | key | %i(certificate key)
- true | cert | key | []
- false | nil | nil | []
- false | cert | nil | %i(key)
- false | nil | key | %i(key)
- false | cert | key | []
+ true | nil | nil | false | %i(certificate key)
+ true | nil | nil | true | []
+ true | cert | nil | false | %i(key)
+ true | cert | nil | true | %i(key)
+ true | nil | key | false | %i(certificate key)
+ true | nil | key | true | %i(key)
+ true | cert | key | false | []
+ true | cert | key | true | []
+ false | nil | nil | false | []
+ false | nil | nil | true | []
+ false | cert | nil | false | %i(key)
+ false | cert | nil | true | %i(key)
+ false | nil | key | false | %i(key)
+ false | nil | key | true | %i(key)
+ false | cert | key | false | []
+ false | cert | key | true | []
end
with_them do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 1bc092fa41a..927c072be10 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -213,7 +213,7 @@ describe Project do
.only_integer
.is_greater_than_or_equal_to(10.minutes)
.is_less_than(1.month)
- .with_message('needs to be beetween 10 minutes and 1 month')
+ .with_message('needs to be between 10 minutes and 1 month')
end
it 'does not allow new projects beyond user limits' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index a4d177da0be..5cfa64fd764 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -530,6 +530,17 @@ describe User do
end
describe 'before save hook' do
+ context '#default_private_profile_to_false' do
+ let(:user) { create(:user, private_profile: true) }
+
+ it 'converts nil to false' do
+ user.private_profile = nil
+ user.save!
+
+ expect(user.private_profile).to eq false
+ end
+ end
+
context 'when saving an external user' do
let(:user) { create(:user) }
let(:external_user) { create(:user, external: true) }
@@ -1127,6 +1138,7 @@ describe User do
expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group)
expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme)
expect(user.external).to be_falsey
+ expect(user.private_profile).to eq false
end
end
@@ -2931,7 +2943,7 @@ describe User do
let(:user) { create(:user, username: username) }
context 'when the user is updated' do
- context 'when the username is changed' do
+ context 'when the username or name is changed' do
let(:new_username) { 'bar' }
it 'changes the namespace (just to compare to when username is not changed)' do
@@ -2942,16 +2954,24 @@ describe User do
end.to change { user.namespace.updated_at }
end
- it 'updates the namespace name' do
+ it 'updates the namespace path when the username was changed' do
user.update!(username: new_username)
- expect(user.namespace.name).to eq(new_username)
+ expect(user.namespace.path).to eq(new_username)
end
- it 'updates the namespace path' do
- user.update!(username: new_username)
+ it 'updates the namespace name if the name was changed' do
+ user.update!(name: 'New name')
- expect(user.namespace.path).to eq(new_username)
+ expect(user.namespace.name).to eq('New name')
+ end
+
+ it 'updates nested routes for the namespace if the name was changed' do
+ project = create(:project, namespace: user.namespace)
+
+ user.update!(name: 'New name')
+
+ expect(project.route.reload.name).to include('New name')
end
context 'when there is a validation error (namespace name taken) while updating namespace' do
diff --git a/spec/policies/ci/trigger_policy_spec.rb b/spec/policies/ci/trigger_policy_spec.rb
index d8a63066265..e9a85890082 100644
--- a/spec/policies/ci/trigger_policy_spec.rb
+++ b/spec/policies/ci/trigger_policy_spec.rb
@@ -3,52 +3,24 @@ require 'spec_helper'
describe Ci::TriggerPolicy do
let(:user) { create(:user) }
let(:project) { create(:project) }
- let(:trigger) { create(:ci_trigger, project: project, owner: owner) }
+ let(:trigger) { create(:ci_trigger, project: project, owner: create(:user)) }
- let(:policies) do
- described_class.new(user, trigger)
- end
-
- shared_examples 'allows to admin and manage trigger' do
- it 'does include ability to admin trigger' do
- expect(policies).to be_allowed :admin_trigger
- end
-
- it 'does include ability to manage trigger' do
- expect(policies).to be_allowed :manage_trigger
- end
- end
-
- shared_examples 'allows to manage trigger' do
- it 'does not include ability to admin trigger' do
- expect(policies).not_to be_allowed :admin_trigger
- end
-
- it 'does include ability to manage trigger' do
- expect(policies).to be_allowed :manage_trigger
- end
- end
-
- shared_examples 'disallows to admin and manage trigger' do
- it 'does not include ability to admin trigger' do
- expect(policies).not_to be_allowed :admin_trigger
- end
-
- it 'does not include ability to manage trigger' do
- expect(policies).not_to be_allowed :manage_trigger
- end
- end
+ subject { described_class.new(user, trigger) }
describe '#rules' do
context 'when owner is undefined' do
- let(:owner) { nil }
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: false)
+ trigger.update_attribute(:owner, nil)
+ end
context 'when user is maintainer of the project' do
before do
project.add_maintainer(user)
end
- it_behaves_like 'allows to admin and manage trigger'
+ it { is_expected.to be_allowed(:manage_trigger) }
+ it { is_expected.not_to be_allowed(:admin_trigger) }
end
context 'when user is developer of the project' do
@@ -56,35 +28,63 @@ describe Ci::TriggerPolicy do
project.add_developer(user)
end
- it_behaves_like 'disallows to admin and manage trigger'
+ it { is_expected.not_to be_allowed(:manage_trigger) }
+ it { is_expected.not_to be_allowed(:admin_trigger) }
end
- context 'when user is not member of the project' do
- it_behaves_like 'disallows to admin and manage trigger'
+ context 'when :use_legacy_pipeline_triggers feature flag is enabled' do
+ before do
+ stub_feature_flags(use_legacy_pipeline_triggers: true)
+ end
+
+ context 'when user is maintainer of the project' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it { is_expected.to be_allowed(:manage_trigger) }
+ it { is_expected.to be_allowed(:admin_trigger) }
+ end
+
+ context 'when user is developer of the project' do
+ before do
+ project.add_developer(user)
+ end
+
+ it { is_expected.not_to be_allowed(:manage_trigger) }
+ it { is_expected.not_to be_allowed(:admin_trigger) }
+ end
+
+ context 'when user is not member of the project' do
+ it { is_expected.not_to be_allowed(:manage_trigger) }
+ it { is_expected.not_to be_allowed(:admin_trigger) }
+ end
end
end
context 'when owner is an user' do
- let(:owner) { user }
+ before do
+ trigger.update!(owner: user)
+ end
context 'when user is maintainer of the project' do
before do
project.add_maintainer(user)
end
- it_behaves_like 'allows to admin and manage trigger'
+ it { is_expected.to be_allowed(:manage_trigger) }
+ it { is_expected.to be_allowed(:admin_trigger) }
end
end
context 'when owner is another user' do
- let(:owner) { create(:user) }
-
context 'when user is maintainer of the project' do
before do
project.add_maintainer(user)
end
- it_behaves_like 'allows to manage trigger'
+ it { is_expected.to be_allowed(:manage_trigger) }
+ it { is_expected.not_to be_allowed(:admin_trigger) }
end
context 'when user is developer of the project' do
@@ -92,11 +92,13 @@ describe Ci::TriggerPolicy do
project.add_developer(user)
end
- it_behaves_like 'disallows to admin and manage trigger'
+ it { is_expected.not_to be_allowed(:manage_trigger) }
+ it { is_expected.not_to be_allowed(:admin_trigger) }
end
context 'when user is not member of the project' do
- it_behaves_like 'disallows to admin and manage trigger'
+ it { is_expected.not_to be_allowed(:manage_trigger) }
+ it { is_expected.not_to be_allowed(:admin_trigger) }
end
end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 3df5d9412f8..204e378f7be 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -281,7 +281,7 @@ describe API::Commits do
end
it 'does not increment the usage counters using access token authentication' do
- expect(::Gitlab::WebIdeCommitsCounter).not_to receive(:increment)
+ expect(::Gitlab::UsageDataCounters::WebIdeCommitsCounter).not_to receive(:increment)
post api(url, user), params: valid_c_params
end
diff --git a/spec/requests/api/group_clusters_spec.rb b/spec/requests/api/group_clusters_spec.rb
new file mode 100644
index 00000000000..46e3dd650cc
--- /dev/null
+++ b/spec/requests/api/group_clusters_spec.rb
@@ -0,0 +1,452 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::GroupClusters do
+ include KubernetesHelpers
+
+ let(:current_user) { create(:user) }
+ let(:developer_user) { create(:user) }
+ let(:group) { create(:group, :private) }
+
+ before do
+ group.add_developer(developer_user)
+ group.add_maintainer(current_user)
+ end
+
+ describe 'GET /groups/:id/clusters' do
+ let!(:extra_cluster) { create(:cluster, :provided_by_gcp, :group) }
+
+ let!(:clusters) do
+ create_list(:cluster, 5, :provided_by_gcp, :group, :production_environment,
+ groups: [group])
+ end
+
+ context 'non-authorized user' do
+ it 'responds with 403' do
+ get api("/groups/#{group.id}/clusters", developer_user)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ get api("/groups/#{group.id}/clusters", current_user)
+ end
+
+ it 'responds with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'includes pagination headers' do
+ expect(response).to include_pagination_headers
+ end
+
+ it 'only include authorized clusters' do
+ cluster_ids = json_response.map { |cluster| cluster['id'] }
+
+ expect(cluster_ids).to match_array(clusters.pluck(:id))
+ expect(cluster_ids).not_to include(extra_cluster.id)
+ end
+ end
+ end
+
+ describe 'GET /groups/:id/clusters/:cluster_id' do
+ let(:cluster_id) { cluster.id }
+
+ let(:platform_kubernetes) do
+ create(:cluster_platform_kubernetes, :configured)
+ end
+
+ let(:cluster) do
+ create(:cluster, :group, :provided_by_gcp, :with_domain,
+ platform_kubernetes: platform_kubernetes,
+ user: current_user,
+ groups: [group])
+ end
+
+ context 'non-authorized user' do
+ it 'responds with 403' do
+ get api("/groups/#{group.id}/clusters/#{cluster_id}", developer_user)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ get api("/groups/#{group.id}/clusters/#{cluster_id}", current_user)
+ end
+
+ it 'returns specific cluster' do
+ expect(json_response['id']).to eq(cluster.id)
+ end
+
+ it 'returns cluster information' do
+ expect(json_response['provider_type']).to eq('gcp')
+ expect(json_response['platform_type']).to eq('kubernetes')
+ expect(json_response['environment_scope']).to eq('*')
+ expect(json_response['cluster_type']).to eq('group_type')
+ expect(json_response['domain']).to eq('example.com')
+ end
+
+ it 'returns group information' do
+ cluster_group = json_response['group']
+
+ expect(cluster_group['id']).to eq(group.id)
+ expect(cluster_group['name']).to eq(group.name)
+ expect(cluster_group['web_url']).to eq(group.web_url)
+ end
+
+ it 'returns kubernetes platform information' do
+ platform = json_response['platform_kubernetes']
+
+ expect(platform['api_url']).to eq('https://kubernetes.example.com')
+ expect(platform['ca_cert']).to be_present
+ end
+
+ it 'returns user information' do
+ user = json_response['user']
+
+ expect(user['id']).to eq(current_user.id)
+ expect(user['username']).to eq(current_user.username)
+ end
+
+ it 'returns GCP provider information' do
+ gcp_provider = json_response['provider_gcp']
+
+ expect(gcp_provider['cluster_id']).to eq(cluster.id)
+ expect(gcp_provider['status_name']).to eq('created')
+ expect(gcp_provider['gcp_project_id']).to eq('test-gcp-project')
+ expect(gcp_provider['zone']).to eq('us-central1-a')
+ expect(gcp_provider['machine_type']).to eq('n1-standard-2')
+ expect(gcp_provider['num_nodes']).to eq(3)
+ expect(gcp_provider['endpoint']).to eq('111.111.111.111')
+ end
+
+ context 'when cluster has no provider' do
+ let(:cluster) do
+ create(:cluster, :group, :provided_by_user,
+ groups: [group])
+ end
+
+ it 'does not include GCP provider info' do
+ expect(json_response['provider_gcp']).not_to be_present
+ end
+ end
+
+ context 'with non-existing cluster' do
+ let(:cluster_id) { 123 }
+
+ it 'returns 404' do
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+
+ shared_context 'kubernetes calls stubbed' do
+ before do
+ stub_kubeclient_discover(api_url)
+ end
+ end
+
+ describe 'POST /groups/:id/clusters/user' do
+ include_context 'kubernetes calls stubbed'
+
+ let(:api_url) { 'https://kubernetes.example.com' }
+ let(:authorization_type) { 'rbac' }
+
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: api_url,
+ token: 'sample-token',
+ authorization_type: authorization_type
+ }
+ end
+
+ let(:cluster_params) do
+ {
+ name: 'test-cluster',
+ domain: 'domain.example.com',
+ managed: false,
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ context 'non-authorized user' do
+ it 'responds with 403' do
+ post api("/groups/#{group.id}/clusters/user", developer_user), params: cluster_params
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ post api("/groups/#{group.id}/clusters/user", current_user), params: cluster_params
+ end
+
+ context 'with valid params' do
+ it 'responds with 201' do
+ expect(response).to have_gitlab_http_status(201)
+ end
+
+ it 'creates a new Cluster::Cluster' do
+ cluster_result = Clusters::Cluster.find(json_response["id"])
+ platform_kubernetes = cluster_result.platform
+
+ expect(cluster_result).to be_user
+ expect(cluster_result).to be_kubernetes
+ expect(cluster_result.group).to eq(group)
+ expect(cluster_result.name).to eq('test-cluster')
+ expect(cluster_result.domain).to eq('domain.example.com')
+ expect(cluster_result.managed).to be_falsy
+ expect(platform_kubernetes.rbac?).to be_truthy
+ expect(platform_kubernetes.api_url).to eq(api_url)
+ expect(platform_kubernetes.token).to eq('sample-token')
+ end
+ end
+
+ context 'when user does not indicate authorization type' do
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: api_url,
+ token: 'sample-token'
+ }
+ end
+
+ it 'defaults to RBAC' do
+ cluster_result = Clusters::Cluster.find(json_response['id'])
+
+ expect(cluster_result.platform_kubernetes.rbac?).to be_truthy
+ end
+ end
+
+ context 'when user sets authorization type as ABAC' do
+ let(:authorization_type) { 'abac' }
+
+ it 'creates an ABAC cluster' do
+ cluster_result = Clusters::Cluster.find(json_response['id'])
+
+ expect(cluster_result.platform.abac?).to be_truthy
+ end
+ end
+
+ context 'with invalid params' do
+ let(:api_url) { 'invalid_api_url' }
+
+ it 'responds with 400' do
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'does not create a new Clusters::Cluster' do
+ expect(group.reload.clusters).to be_empty
+ end
+
+ it 'returns validation errors' do
+ expect(json_response['message']['platform_kubernetes.api_url'].first).to be_present
+ end
+ end
+ end
+
+ context 'when user tries to add multiple clusters' do
+ before do
+ create(:cluster, :provided_by_gcp, :group,
+ groups: [group])
+
+ post api("/groups/#{group.id}/clusters/user", current_user), params: cluster_params
+ end
+
+ it 'responds with 400' do
+ expect(response).to have_gitlab_http_status(400)
+ expect(json_response['message']['base'].first).to include('Instance does not support multiple Kubernetes clusters')
+ end
+ end
+
+ context 'non-authorized user' do
+ before do
+ post api("/groups/#{group.id}/clusters/user", developer_user), params: cluster_params
+ end
+
+ it 'responds with 403' do
+ expect(response).to have_gitlab_http_status(403)
+
+ expect(json_response['message']).to eq('403 Forbidden')
+ end
+ end
+ end
+
+ describe 'PUT /groups/:id/clusters/:cluster_id' do
+ include_context 'kubernetes calls stubbed'
+
+ let(:api_url) { 'https://kubernetes.example.com' }
+
+ let(:update_params) do
+ {
+ domain: domain,
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ let(:domain) { 'new-domain.com' }
+ let(:platform_kubernetes_attributes) { {} }
+
+ let(:cluster) do
+ create(:cluster, :group, :provided_by_gcp,
+ groups: [group], domain: 'old-domain.com')
+ end
+
+ context 'non-authorized user' do
+ it 'responds with 403' do
+ put api("/groups/#{group.id}/clusters/#{cluster.id}", developer_user), params: update_params
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ put api("/groups/#{group.id}/clusters/#{cluster.id}", current_user), params: update_params
+
+ cluster.reload
+ end
+
+ context 'with valid params' do
+ it 'responds with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'updates cluster attributes' do
+ expect(cluster.domain).to eq('new-domain.com')
+ end
+ end
+
+ context 'with invalid params' do
+ let(:domain) { 'invalid domain' }
+
+ it 'responds with 400' do
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'does not update cluster attributes' do
+ expect(cluster.domain).to eq('old-domain.com')
+ end
+
+ it 'returns validation errors' do
+ expect(json_response['message']['domain'].first).to match('contains invalid characters (valid characters: [a-z0-9\\-])')
+ end
+ end
+
+ context 'with a GCP cluster' do
+ context 'when user tries to change GCP specific fields' do
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: 'https://new-api-url.com',
+ token: 'new-sample-token'
+ }
+ end
+
+ it 'responds with 400' do
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'returns validation error' do
+ expect(json_response['message']['platform_kubernetes.base'].first).to eq('Cannot modify managed Kubernetes cluster')
+ end
+ end
+
+ context 'when user tries to change domain' do
+ let(:domain) { 'new-domain.com' }
+
+ it 'responds with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+ end
+
+ context 'with an user cluster' do
+ let(:api_url) { 'https://new-api-url.com' }
+
+ let(:cluster) do
+ create(:cluster, :group, :provided_by_user,
+ groups: [group])
+ end
+
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: api_url,
+ token: 'new-sample-token'
+ }
+ end
+
+ let(:update_params) do
+ {
+ name: 'new-name',
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ it 'responds with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'updates platform kubernetes attributes' do
+ platform_kubernetes = cluster.platform_kubernetes
+
+ expect(cluster.name).to eq('new-name')
+ expect(platform_kubernetes.api_url).to eq('https://new-api-url.com')
+ expect(platform_kubernetes.token).to eq('new-sample-token')
+ end
+ end
+
+ context 'with a cluster that does not belong to user' do
+ let(:cluster) { create(:cluster, :group, :provided_by_user) }
+
+ it 'responds with 404' do
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+
+ describe 'DELETE /groups/:id/clusters/:cluster_id' do
+ let(:cluster_params) { { cluster_id: cluster.id } }
+
+ let(:cluster) do
+ create(:cluster, :group, :provided_by_gcp,
+ groups: [group])
+ end
+
+ context 'non-authorized user' do
+ it 'responds with 403' do
+ delete api("/groups/#{group.id}/clusters/#{cluster.id}", developer_user), params: cluster_params
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ delete api("/groups/#{group.id}/clusters/#{cluster.id}", current_user), params: cluster_params
+ end
+
+ it 'responds with 204' do
+ expect(response).to have_gitlab_http_status(204)
+ end
+
+ it 'deletes the cluster' do
+ expect(Clusters::Cluster.exists?(id: cluster.id)).to be_falsy
+ end
+
+ context 'with a cluster that does not belong to user' do
+ let(:cluster) { create(:cluster, :group, :provided_by_user) }
+
+ it 'responds with 404' do
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index fcbff19bd61..3ab1818bebb 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -474,7 +474,7 @@ describe API::Internal do
'ssh',
{
authentication_abilities: [:read_project, :download_code, :push_code],
- namespace_path: project.namespace.name,
+ namespace_path: project.namespace.path,
project_path: project.path,
redirected_path: nil
}
@@ -753,7 +753,7 @@ describe API::Internal do
end
describe 'GET /internal/merge_request_urls' do
- let(:repo_name) { "#{project.namespace.name}/#{project.path}" }
+ let(:repo_name) { "#{project.full_path}" }
let(:changes) { URI.escape("#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch") }
before do
@@ -765,7 +765,7 @@ describe API::Internal do
expect(json_response).to match [{
"branch_name" => "new_branch",
- "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
+ "url" => "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
"new_merge_request" => true
}]
end
@@ -786,7 +786,7 @@ describe API::Internal do
expect(json_response).to match [{
"branch_name" => "new_branch",
- "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
+ "url" => "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
"new_merge_request" => true
}]
end
@@ -927,7 +927,7 @@ describe API::Internal do
expect(json_response['merge_request_urls']).to match [{
"branch_name" => branch_name,
- "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{branch_name}",
+ "url" => "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{branch_name}",
"new_merge_request" => true
}]
end
@@ -970,7 +970,7 @@ describe API::Internal do
expect(json_response['merge_request_urls']).to match [{
'branch_name' => branch_name,
- 'url' => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/1",
+ 'url' => "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/1",
'new_merge_request' => false
}]
end
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index a6e08ab3ab6..e8ed016db69 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -257,12 +257,22 @@ describe API::ProjectClusters do
post api("/projects/#{project.id}/clusters/user", current_user), params: cluster_params
end
+ it 'responds with 400' do
+ expect(response).to have_gitlab_http_status(400)
+
+ expect(json_response['message']['base'].first).to eq('Instance does not support multiple Kubernetes clusters')
+ end
+ end
+
+ context 'non-authorized user' do
+ before do
+ post api("/projects/#{project.id}/clusters/user", developer_user), params: cluster_params
+ end
+
it 'responds with 403' do
expect(response).to have_gitlab_http_status(403)
- end
- it 'returns an appropriate message' do
- expect(json_response['message']).to include('Instance does not support multiple Kubernetes clusters')
+ expect(json_response['message']).to eq('403 Forbidden')
end
end
end
diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb
index 3e0b478abb3..8abdcaa2e0e 100644
--- a/spec/requests/api/search_spec.rb
+++ b/spec/requests/api/search_spec.rb
@@ -89,7 +89,7 @@ describe API::Search do
it 'returns empty array' do
get api('/search', user), params: { scope: 'milestones', search: 'awesome' }
- milestones = JSON.parse(response.body)
+ milestones = json_response
expect(milestones).to be_empty
end
@@ -356,7 +356,7 @@ describe API::Search do
it 'returns empty array' do
get api("/projects/#{project.id}/search", user), params: { scope: 'milestones', search: 'awesome' }
- milestones = JSON.parse(response.body)
+ milestones = json_response
expect(milestones).to be_empty
end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 3f79e332b90..91cb8760a04 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -85,9 +85,7 @@ describe API::Services do
include_context service
# inject some properties into the service
- before do
- initialize_service(service)
- end
+ let!(:initialized_service) { initialize_service(service) }
it 'returns authentication error when unauthenticated' do
get api("/projects/#{project.id}/services/#{dashed_service}")
@@ -108,6 +106,15 @@ describe API::Services do
expect(json_response['properties'].keys).to match_array(service_instance.api_field_names)
end
+ it "returns empty hash if properties are empty" do
+ # deprecated services are not valid for update
+ initialized_service.update_attribute(:properties, {})
+ get api("/projects/#{project.id}/services/#{dashed_service}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['properties'].keys).to be_empty
+ end
+
it "returns error when authenticated but not a project owner" do
project.add_developer(user2)
get api("/projects/#{project.id}/services/#{dashed_service}", user2)
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 46925daf40a..0ad50e5347a 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -745,6 +745,14 @@ describe API::Users do
expect(user.reload.private_profile).to eq(true)
end
+ it "updates private profile when nil is given to false" do
+ admin.update(private_profile: true)
+
+ put api("/users/#{user.id}", admin), params: { private_profile: nil }
+
+ expect(user.reload.private_profile).to eq(false)
+ end
+
it "does not update admin status" do
put api("/users/#{admin_user.id}", admin), params: { can_create_group: false }
diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb
index 1781759c54b..dc25e4d808e 100644
--- a/spec/requests/lfs_http_spec.rb
+++ b/spec/requests/lfs_http_spec.rb
@@ -1439,8 +1439,4 @@ describe 'Git LFS API and storage' do
post(url, params: params, headers: headers)
end
-
- def json_response
- @json_response ||= JSON.parse(response.body)
- end
end
diff --git a/spec/requests/lfs_locks_api_spec.rb b/spec/requests/lfs_locks_api_spec.rb
index 5b7b3d2fdd6..11436e5cd0c 100644
--- a/spec/requests/lfs_locks_api_spec.rb
+++ b/spec/requests/lfs_locks_api_spec.rb
@@ -163,8 +163,4 @@ describe 'Git LFS File Locking API' do
def do_get(url, params = nil, headers = nil)
get(url, params: (params || {}), headers: (headers || {}).merge('Content-Type' => LfsRequest::CONTENT_TYPE))
end
-
- def json_response
- @json_response ||= JSON.parse(response.body)
- end
end
diff --git a/spec/routing/environments_spec.rb b/spec/routing/environments_spec.rb
index aacbe300966..28b3e79c1ff 100644
--- a/spec/routing/environments_spec.rb
+++ b/spec/routing/environments_spec.rb
@@ -9,7 +9,7 @@ describe 'environments routing' do
end
let(:environments_route) do
- "#{project.namespace.name}/#{project.name}/environments/"
+ "#{project.full_path}/environments/"
end
describe 'routing environment folders' do
@@ -36,13 +36,12 @@ describe 'environments routing' do
end
def get_folder(folder)
- get("#{project.namespace.name}/#{project.name}/" \
- "environments/folders/#{folder}")
+ get("#{project.full_path}/environments/folders/#{folder}")
end
def folder_action(**opts)
- options = { namespace_id: project.namespace.name,
- project_id: project.name }
+ options = { namespace_id: project.namespace.path,
+ project_id: project.path }
['projects/environments#folder', options.merge(opts)]
end
diff --git a/spec/rubocop/cop/qa/element_with_pattern_spec.rb b/spec/rubocop/cop/qa/element_with_pattern_spec.rb
index ef20d9a1f26..fee390caa9f 100644
--- a/spec/rubocop/cop/qa/element_with_pattern_spec.rb
+++ b/spec/rubocop/cop/qa/element_with_pattern_spec.rb
@@ -23,9 +23,9 @@ describe RuboCop::Cop::QA::ElementWithPattern do
expect_offense(<<-RUBY)
view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter, 'search_field_tag :filter'
- ^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use a pattern for element, create a corresponding `qa-groups-filter` instead.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use a pattern for element, create a corresponding `data-qa-selector=groups_filter` instead.
element :groups_filter_placeholder, /Search by name/
- ^^^^^^^^^^^^^^ Don't use a pattern for element, create a corresponding `qa-groups-filter-placeholder` instead.
+ ^^^^^^^^^^^^^^ Don't use a pattern for element, create a corresponding `data-qa-selector=groups_filter_placeholder` instead.
end
RUBY
end
diff --git a/spec/serializers/environment_status_entity_spec.rb b/spec/serializers/environment_status_entity_spec.rb
index f421432e8d6..cb4749f019f 100644
--- a/spec/serializers/environment_status_entity_spec.rb
+++ b/spec/serializers/environment_status_entity_spec.rb
@@ -70,7 +70,7 @@ describe EnvironmentStatusEntity do
it 'returns metrics url' do
expect(subject[:metrics_url])
- .to eq("/#{project.namespace.name}/#{project.name}/environments/#{environment.id}/deployments/#{deployment.iid}/metrics")
+ .to eq("/#{project.full_path}/environments/#{environment.id}/deployments/#{deployment.iid}/metrics")
end
end
diff --git a/spec/services/audit_event_service_spec.rb b/spec/services/audit_event_service_spec.rb
index 32fd98e6ef9..e42bff607b2 100644
--- a/spec/services/audit_event_service_spec.rb
+++ b/spec/services/audit_event_service_spec.rb
@@ -10,11 +10,8 @@ describe AuditEventService do
let(:logger) { instance_double(Gitlab::AuditJsonLogger) }
describe '#security_event' do
- before do
- expect(service).to receive(:file_logger).and_return(logger)
- end
-
it 'creates an event and logs to a file' do
+ expect(service).to receive(:file_logger).and_return(logger)
expect(logger).to receive(:info).with(author_id: user.id,
entity_id: project.id,
entity_type: "Project",
@@ -22,5 +19,32 @@ describe AuditEventService do
expect { service.security_event }.to change(SecurityEvent, :count).by(1)
end
+
+ it 'formats from and to fields' do
+ service = described_class.new(
+ user, project,
+ {
+ from: true,
+ to: false,
+ action: :create,
+ target_id: 1
+ })
+ expect(service).to receive(:file_logger).and_return(logger)
+ expect(logger).to receive(:info).with(author_id: user.id,
+ entity_type: 'Project',
+ entity_id: project.id,
+ from: 'true',
+ to: 'false',
+ action: :create,
+ target_id: 1)
+
+ expect { service.security_event }.to change(SecurityEvent, :count).by(1)
+
+ details = SecurityEvent.last.details
+ expect(details[:from]).to be true
+ expect(details[:to]).to be false
+ expect(details[:action]).to eq(:create)
+ expect(details[:target_id]).to eq(1)
+ end
end
end
diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb
index 1bfb5602df2..cf84ec8fd4c 100644
--- a/spec/services/boards/issues/move_service_spec.rb
+++ b/spec/services/boards/issues/move_service_spec.rb
@@ -68,8 +68,8 @@ describe Boards::Issues::MoveService do
project.add_developer(user)
end
- it 'returns false if list of issues is empty' do
- expect(described_class.new(group, user, params).execute_multiple([])).to eq(false)
+ it 'returns the expected result if list of issues is empty' do
+ expect(described_class.new(group, user, params).execute_multiple([])).to eq({ count: 0, success: false, issues: [] })
end
context 'moving multiple issues' do
diff --git a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
index 9ab83d913f5..a948b442441 100644
--- a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
+++ b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
@@ -41,7 +41,7 @@ describe Clusters::Applications::CheckUninstallProgressService do
end
end
- context 'when application is installing' do
+ context 'when application is uninstalling' do
RESCHEDULE_PHASES.each { |phase| it_behaves_like 'a not yet terminated installation', phase }
context 'when installation POD succeeded' do
@@ -56,6 +56,12 @@ describe Clusters::Applications::CheckUninstallProgressService do
service.execute
end
+ it 'runs application post_uninstall' do
+ expect(application).to receive(:post_uninstall).and_call_original
+
+ service.execute
+ end
+
it 'destroys the application' do
expect(worker_class).not_to receive(:perform_in)
diff --git a/spec/services/issuable/clone/content_rewriter_spec.rb b/spec/services/issuable/clone/content_rewriter_spec.rb
index 230e1123280..3479c20862a 100644
--- a/spec/services/issuable/clone/content_rewriter_spec.rb
+++ b/spec/services/issuable/clone/content_rewriter_spec.rb
@@ -165,5 +165,18 @@ describe Issuable::Clone::ContentRewriter do
expect(note.note_html).not_to eq(new_note.note_html)
end
end
+
+ context "discussion notes" do
+ let(:note) { create(:note, noteable: original_issue, note: "sample note", project: project1) }
+ let!(:discussion) { create(:discussion_note_on_issue, in_reply_to: note, note: "reply to sample note") }
+
+ it 'rewrites discussion correctly' do
+ subject.execute
+
+ expect(new_issue.notes.count).to eq(original_issue.notes.count)
+ expect(new_issue.notes.where(discussion_id: discussion.discussion_id).count).to eq(0)
+ expect(original_issue.notes.where(discussion_id: discussion.discussion_id).count).to eq(1)
+ end
+ end
end
end
diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb
index 0933c6d4336..9e7a5260ca4 100644
--- a/spec/services/merge_requests/get_urls_service_spec.rb
+++ b/spec/services/merge_requests/get_urls_service_spec.rb
@@ -8,8 +8,8 @@ describe MergeRequests::GetUrlsService do
let(:project) { create(:project, :public, :repository) }
let(:service) { described_class.new(project) }
let(:source_branch) { "merge-test" }
- let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{source_branch}" }
- let(:show_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/#{merge_request.iid}" }
+ let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{source_branch}" }
+ let(:show_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/#{merge_request.iid}" }
let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
let(:deleted_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 #{Gitlab::Git::BLANK_SHA} refs/heads/#{source_branch}" }
let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
@@ -119,7 +119,7 @@ describe MergeRequests::GetUrlsService do
let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" }
let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/markdown" }
let(:changes) { "#{new_branch_changes}\n#{existing_branch_changes}" }
- let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" }
+ let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" }
it 'returns 2 urls for both creating new and showing merge request' do
result = service.execute(changes)
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 1d7bf91fda1..3e3de051732 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1844,7 +1844,7 @@ describe NotificationService, :mailer do
describe 'ProjectMember' do
let(:project) { create(:project) }
- set(:added_user) { create(:user) }
+ let(:added_user) { create(:user) }
describe '#new_access_request' do
context 'for a project in a user namespace' do
diff --git a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
index 8d43ce4f662..af79a42b611 100644
--- a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
+++ b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
@@ -12,6 +12,12 @@ describe PagesDomains::ObtainLetsEncryptCertificateService do
stub_lets_encrypt_settings
end
+ around do |example|
+ Sidekiq::Testing.fake! do
+ example.run
+ end
+ end
+
def expect_to_create_acme_challenge
expect(::PagesDomains::CreateAcmeOrderService).to receive(:new).with(pages_domain)
.and_wrap_original do |m, *args|
diff --git a/spec/services/self_monitoring/project/create_service_spec.rb b/spec/services/self_monitoring/project/create_service_spec.rb
new file mode 100644
index 00000000000..d11e27c6d52
--- /dev/null
+++ b/spec/services/self_monitoring/project/create_service_spec.rb
@@ -0,0 +1,201 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe SelfMonitoring::Project::CreateService do
+ describe '#execute' do
+ 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)
+ end
+
+ context 'without admin users' do
+ it 'returns error' 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
+ )
+ end
+ end
+
+ context 'with admin users' do
+ let(:project) { result[:project] }
+
+ let!(:user) { create(:user, :admin) }
+
+ before do
+ allow(ApplicationSetting)
+ .to receive(:current)
+ .and_return(
+ ApplicationSetting.build_from_defaults(allow_local_requests_from_hooks_and_services: true)
+ )
+ end
+
+ shared_examples 'has prometheus service' do |listen_address|
+ it do
+ expect(result[:status]).to eq(:success)
+
+ prometheus = project.prometheus_service
+ 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 project with internal visibility' do
+ expect(result[:status]).to eq(:success)
+ expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
+ expect(project).to be_persisted
+ end
+
+ it 'creates project with internal visibility even when internal visibility is restricted' do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
+
+ expect(result[:status]).to eq(:success)
+ expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
+ expect(project).to be_persisted
+ end
+
+ it 'creates project with correct name and description' do
+ expect(result[:status]).to eq(:success)
+ expect(project.name).to eq(described_class::DEFAULT_NAME)
+ expect(project.description).to eq(described_class::DEFAULT_DESCRIPTION)
+ end
+
+ it 'adds all admins as maintainers' do
+ admin1 = create(:user, :admin)
+ admin2 = create(:user, :admin)
+ create(:user)
+
+ expect(result[:status]).to eq(:success)
+ expect(project.owner).to eq(user)
+ expect(project.members.collect(&:user)).to contain_exactly(user, admin1, admin2)
+ expect(project.members.collect(&:access_level)).to contain_exactly(
+ Gitlab::Access::MAINTAINER,
+ Gitlab::Access::MAINTAINER,
+ Gitlab::Access::MAINTAINER
+ )
+ end
+
+ # This should pass when https://gitlab.com/gitlab-org/gitlab-ce/issues/44496
+ # is complete and the prometheus listen address is added to the whitelist.
+ # context 'when local requests from hooks and services are not allowed' do
+ # before do
+ # allow(ApplicationSetting)
+ # .to receive(:current)
+ # .and_return(
+ # ApplicationSetting.build_from_defaults(allow_local_requests_from_hooks_and_services: false)
+ # )
+ # end
+
+ # it_behaves_like 'has prometheus service', 'http://localhost:9090'
+ # end
+
+ context 'with non default prometheus address' do
+ before do
+ prometheus_settings.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
+ expect(result).to include(status: :success)
+ expect(project.prometheus_service).to be_nil
+ end
+ end
+
+ context 'when prometheus setting is disabled in gitlab.yml' do
+ before do
+ prometheus_settings.enable = false
+ end
+
+ it 'does not configure prometheus' do
+ expect(result).to include(status: :success)
+ expect(project.prometheus_service).to be_nil
+ end
+ end
+
+ context 'when prometheus listen address is blank in gitlab.yml' do
+ before do
+ prometheus_settings.listen_address = ''
+ end
+
+ it 'does not configure prometheus' do
+ expect(result).to include(status: :success)
+ expect(project.prometheus_service).to be_nil
+ end
+ end
+
+ context 'when project cannot be created' do
+ let(:project) { build(:project) }
+
+ before do
+ project.errors.add(:base, "Test error")
+
+ expect_next_instance_of(::Projects::CreateService) do |project_create_service|
+ expect(project_create_service).to receive(:execute)
+ .and_return(project)
+ end
+ end
+
+ 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
+ })
+ end
+ end
+
+ context 'when user cannot be added to project' do
+ before do
+ subject.instance_variable_set(:@instance_admins, [user, build(:user, :admin)])
+ end
+
+ 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_project_members
+ })
+ end
+ end
+
+ context 'when prometheus manual configuration cannot be saved' do
+ before do
+ prometheus_settings.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
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 62fdc039b5e..95e0d8858b9 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -47,7 +47,7 @@ Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
quality_level = Quality::TestLevel.new
RSpec.configure do |config|
- config.use_transactional_fixtures = false
+ config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
config.fixture_path = Rails.root
@@ -103,6 +103,7 @@ RSpec.configure do |config|
config.include RedisHelpers
config.include Rails.application.routes.url_helpers, type: :routing
config.include PolicyHelpers, type: :policy
+ config.include MemoryUsageHelper
if ENV['CI']
# This includes the first try, i.e. tests will be run 4 times before failing.
@@ -289,6 +290,16 @@ RSpec.configure do |config|
config.before(:each, :https_pages_disabled) do |_|
allow(Gitlab.config.pages).to receive(:external_https).and_return(false)
end
+
+ # We can't use an `around` hook here because the wrapping transaction
+ # is not yet opened at the time that is triggered
+ config.prepend_before do
+ Gitlab::Database.set_open_transactions_baseline
+ end
+
+ config.append_after do
+ Gitlab::Database.reset_open_transactions_baseline
+ end
end
# add simpler way to match asset paths containing digest strings
diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb
index edd7de94203..f0dd6c52b74 100644
--- a/spec/support/database_cleaner.rb
+++ b/spec/support/database_cleaner.rb
@@ -26,31 +26,22 @@ RSpec.configure do |config|
end
config.append_after(:context) do
- DatabaseCleaner.clean_with(:deletion, cache_tables: false)
+ delete_from_all_tables!
end
- config.before do
- setup_database_cleaner
- DatabaseCleaner.strategy = :transaction
- end
+ config.around(:each, :delete) do |example|
+ self.class.use_transactional_tests = false
- config.before(:each, :js) do
- DatabaseCleaner.strategy = :deletion, { except: deletion_except_tables, cache_tables: false }
- end
+ example.run
- config.before(:each, :delete) do
- DatabaseCleaner.strategy = :deletion, { except: deletion_except_tables, cache_tables: false }
+ delete_from_all_tables!(except: deletion_except_tables)
end
- config.before(:each, :migration) do
- DatabaseCleaner.strategy = :deletion, { cache_tables: false }
- end
+ config.around(:each, :migration) do |example|
+ self.class.use_transactional_tests = false
- config.before do
- DatabaseCleaner.start
- end
+ example.run
- config.append_after do
- DatabaseCleaner.clean
+ delete_from_all_tables!
end
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index c69fa322073..08622dff6d9 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -1,4 +1,8 @@
module DbCleaner
+ def delete_from_all_tables!(except: nil)
+ DatabaseCleaner.clean_with(:deletion, cache_tables: false, except: except)
+ end
+
def deletion_except_tables
[]
end
diff --git a/spec/support/helpers/memory_usage_helper.rb b/spec/support/helpers/memory_usage_helper.rb
new file mode 100644
index 00000000000..984ea8cc571
--- /dev/null
+++ b/spec/support/helpers/memory_usage_helper.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module MemoryUsageHelper
+ extend ActiveSupport::Concern
+
+ def gather_memory_data(csv_path)
+ write_csv_entry(csv_path,
+ {
+ example_group_path: TestEnv.topmost_example_group[:location],
+ example_group_description: TestEnv.topmost_example_group[:description],
+ time: Time.current,
+ job_name: ENV['CI_JOB_NAME']
+ }.merge(get_memory_usage))
+ end
+
+ def write_csv_entry(path, entry)
+ CSV.open(path, "a", headers: entry.keys, write_headers: !File.exist?(path)) do |file|
+ file << entry.values
+ end
+ end
+
+ def get_memory_usage
+ output, status = Gitlab::Popen.popen(%w(free -m))
+ abort "`free -m` return code is #{status}: #{output}" unless status.zero?
+
+ result = output.split("\n")[1].split(" ")[1..-1]
+ attrs = %i(m_total m_used m_free m_shared m_buffers_cache m_available).freeze
+
+ attrs.zip(result).to_h
+ end
+
+ included do |config|
+ config.after(:all) do
+ gather_memory_data(ENV['MEMORY_TEST_PATH']) if ENV['MEMORY_TEST_PATH']
+ end
+ end
+end
diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb
index cc1a28cb264..272b24f7541 100644
--- a/spec/support/helpers/migrations_helpers.rb
+++ b/spec/support/helpers/migrations_helpers.rb
@@ -18,8 +18,12 @@ module MigrationsHelpers
ActiveRecord::Migrator.migrations_paths
end
+ def migration_context
+ ActiveRecord::MigrationContext.new(migrations_paths)
+ end
+
def migrations
- ActiveRecord::Migrator.migrations(migrations_paths)
+ migration_context.migrations
end
def clear_schema_cache!
@@ -96,8 +100,7 @@ module MigrationsHelpers
def schema_migrate_down!
disable_migrations_output do
- ActiveRecord::Migrator.migrate(migrations_paths,
- migration_schema_version)
+ migration_context.down(migration_schema_version)
end
reset_column_in_all_models
@@ -107,7 +110,7 @@ module MigrationsHelpers
reset_column_in_all_models
disable_migrations_output do
- ActiveRecord::Migrator.migrate(migrations_paths)
+ migration_context.up
end
reset_column_in_all_models
@@ -123,7 +126,7 @@ module MigrationsHelpers
end
def migrate!
- ActiveRecord::Migrator.up(migrations_paths) do |migration|
+ migration_context.up do |migration|
migration.name == described_class.name
end
end
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index e63099d89b7..893b10ea752 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -2,6 +2,7 @@ require 'rspec/mocks'
require 'toml-rb'
module TestEnv
+ extend ActiveSupport::Concern
extend self
ComponentFailedToInstallError = Class.new(StandardError)
@@ -108,6 +109,12 @@ module TestEnv
setup_forked_repo
end
+ included do |config|
+ config.append_before do
+ set_current_example_group
+ end
+ end
+
def disable_mailer
allow_any_instance_of(NotificationService).to receive(:mailer)
.and_return(double.as_null_object)
@@ -297,8 +304,23 @@ module TestEnv
FileUtils.rm_rf(path)
end
+ def current_example_group
+ Thread.current[:current_example_group]
+ end
+
+ # looking for a top-level `describe`
+ def topmost_example_group
+ example_group = current_example_group
+ example_group = example_group[:parent_example_group] until example_group[:parent_example_group].nil?
+ example_group
+ end
+
private
+ def set_current_example_group
+ Thread.current[:current_example_group] = ::RSpec.current_example.metadata[:example_group]
+ end
+
# These are directories that should be preserved at cleanup time
def test_dirs
@test_dirs ||= %w[
diff --git a/spec/support/json_response.rb b/spec/support/json_response.rb
index 210b0e6d867..43d8ab73dde 100644
--- a/spec/support/json_response.rb
+++ b/spec/support/json_response.rb
@@ -1,5 +1,5 @@
RSpec.configure do |config|
- config.include_context 'JSON response'
+ config.include_context 'JSON response', type: :controller
config.include_context 'JSON response', type: :request
config.include_context 'JSON response', :api
end
diff --git a/spec/support/shared_contexts/email_shared_context.rb b/spec/support/shared_contexts/email_shared_context.rb
index 9d806fc524d..4f5d53f9317 100644
--- a/spec/support/shared_contexts/email_shared_context.rb
+++ b/spec/support/shared_contexts/email_shared_context.rb
@@ -1,5 +1,3 @@
-require 'gitlab/email/receiver'
-
shared_context :email_shared_context do
let(:mail_key) { "59d8df8370b7e95c5a49fbf86aeb2c93" }
let(:receiver) { Gitlab::Email::Receiver.new(email_raw) }
diff --git a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
index 0acc9e2a836..f4b02dc5350 100644
--- a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
@@ -46,7 +46,7 @@ shared_examples 'issuable notes filter' do
user.set_notes_filter(UserPreference::NOTES_FILTERS[:only_comments], issuable)
get :discussions, params: params
- discussions = JSON.parse(response.body)
+ discussions = json_response
expect(discussions.count).to eq(1)
expect(discussions.first["notes"].first["system"]).to be(false)
@@ -56,7 +56,7 @@ shared_examples 'issuable notes filter' do
user.set_notes_filter(UserPreference::NOTES_FILTERS[:only_activity], issuable)
get :discussions, params: params
- discussions = JSON.parse(response.body)
+ discussions = json_response
expect(discussions.count).to eq(1)
expect(discussions.first["notes"].first["system"]).to be(true)
diff --git a/spec/support/shared_examples/policies/clusterable_shared_examples.rb b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
index d99f94c76c3..4f9873d53e4 100644
--- a/spec/support/shared_examples/policies/clusterable_shared_examples.rb
+++ b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
@@ -24,14 +24,6 @@ shared_examples 'clusterable policies' do
context 'with no clusters' do
it { expect_allowed(:add_cluster) }
end
-
- context 'with an existing cluster' do
- before do
- cluster
- end
-
- it { expect_disallowed(:add_cluster) }
- end
end
end
end
diff --git a/spec/support/shared_examples/update_invalid_issuable.rb b/spec/support/shared_examples/update_invalid_issuable.rb
index 64568de424e..4cb6d001b9b 100644
--- a/spec/support/shared_examples/update_invalid_issuable.rb
+++ b/spec/support/shared_examples/update_invalid_issuable.rb
@@ -38,7 +38,7 @@ shared_examples 'update invalid issuable' do |klass|
put :update, params: params
expect(response.status).to eq(409)
- expect(JSON.parse(response.body)).to have_key('errors')
+ expect(json_response).to have_key('errors')
end
end
diff --git a/spec/views/notify/pipeline_failed_email.html.haml_spec.rb b/spec/views/notify/pipeline_failed_email.html.haml_spec.rb
index 623237b111a..bf633a118ca 100644
--- a/spec/views/notify/pipeline_failed_email.html.haml_spec.rb
+++ b/spec/views/notify/pipeline_failed_email.html.haml_spec.rb
@@ -28,7 +28,7 @@ describe 'notify/pipeline_failed_email.html.haml' do
expect(rendered).to have_content "Your pipeline has failed"
expect(rendered).to have_content pipeline.project.name
- expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub!(/\s+/, ' ')
+ expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub(/\s+/, ' ')
expect(rendered).to have_content pipeline.commit.author_name
expect(rendered).to have_content "##{pipeline.id}"
expect(rendered).to have_content pipeline.user.name
@@ -45,7 +45,7 @@ describe 'notify/pipeline_failed_email.html.haml' do
expect(rendered).to have_content "Your pipeline has failed"
expect(rendered).to have_content pipeline.project.name
- expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub!(/\s+/, ' ')
+ expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub(/\s+/, ' ')
expect(rendered).to have_content pipeline.commit.author_name
expect(rendered).to have_content "##{pipeline.id}"
expect(rendered).to have_content "by API"
diff --git a/spec/views/notify/pipeline_failed_email.text.erb_spec.rb b/spec/views/notify/pipeline_failed_email.text.erb_spec.rb
index 81245239eba..060274eb56a 100644
--- a/spec/views/notify/pipeline_failed_email.text.erb_spec.rb
+++ b/spec/views/notify/pipeline_failed_email.text.erb_spec.rb
@@ -30,7 +30,7 @@ describe 'notify/pipeline_failed_email.text.erb' do
expect(rendered).to have_content('Your pipeline has failed')
expect(rendered).to have_content(pipeline.project.name)
- expect(rendered).to have_content(pipeline.git_commit_message.truncate(50).gsub!(/\s+/, ' '))
+ expect(rendered).to have_content(pipeline.git_commit_message.truncate(50).gsub(/\s+/, ' '))
expect(rendered).to have_content(pipeline.commit.author_name)
expect(rendered).to have_content("##{pipeline.id}")
expect(rendered).to have_content(pipeline.user.name)
diff --git a/spec/views/notify/pipeline_success_email.html.haml_spec.rb b/spec/views/notify/pipeline_success_email.html.haml_spec.rb
index a876bf13e11..46a6c908863 100644
--- a/spec/views/notify/pipeline_success_email.html.haml_spec.rb
+++ b/spec/views/notify/pipeline_success_email.html.haml_spec.rb
@@ -28,7 +28,7 @@ describe 'notify/pipeline_success_email.html.haml' do
expect(rendered).to have_content "Your pipeline has passed"
expect(rendered).to have_content pipeline.project.name
- expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub!(/\s+/, ' ')
+ expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub(/\s+/, ' ')
expect(rendered).to have_content pipeline.commit.author_name
expect(rendered).to have_content "##{pipeline.id}"
expect(rendered).to have_content pipeline.user.name
@@ -45,7 +45,7 @@ describe 'notify/pipeline_success_email.html.haml' do
expect(rendered).to have_content "Your pipeline has passed"
expect(rendered).to have_content pipeline.project.name
- expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub!(/\s+/, ' ')
+ expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub(/\s+/, ' ')
expect(rendered).to have_content pipeline.commit.author_name
expect(rendered).to have_content "##{pipeline.id}"
expect(rendered).to have_content "by API"
diff --git a/yarn.lock b/yarn.lock
index dc5e0662396..eaa029281d6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -705,10 +705,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.67.0.tgz#c7b94eca13b99fd3aaa737fb6dcc0abc41d3c579"
integrity sha512-hJOmWEs6RkjzyKkb1vc9wwKGZIBIP0coHkxu/KgOoxhBVudpGk4CH7xJ6UuB2TKpb0SEh5CC1CzRZfBYaFhsaA==
-"@gitlab/ui@^5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.5.0.tgz#2000b2ed0c3825dd8c4430191023f4d03c923ecb"
- integrity sha512-6e/AFFLDk/gm4wKnHM9rcpTRqCsWkPKW/Vjsnd6h4wyfif2/TusHeIn/jedQxUaORbO/XZKzg4V5COhXXbCx4w==
+"@gitlab/ui@^5.6.0":
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.6.0.tgz#6b5408050229e2135359f3fce5d0de7718326a0d"
+ integrity sha512-EohpACc5OCK8pOWgwB7/QZUcg3tA9k863ku6Ik9NxaRSKt/JIpQ8RI4wCr4UmqhejZLQMD9VZHLUmc9Sf3Mk9w==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"
@@ -6992,9 +6992,9 @@ lodash.kebabcase@4.1.1:
integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY=
lodash.mergewith@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55"
- integrity sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
+ integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
lodash.snakecase@4.1.1:
version "4.1.1"
@@ -7012,9 +7012,9 @@ lodash.upperfirst@4.3.1:
integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.0, lodash@~4.17.10:
- version "4.17.11"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
- integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
+ version "4.17.14"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
+ integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
log-symbols@^2.0.0, log-symbols@^2.1.0, log-symbols@^2.2.0:
version "2.2.0"