summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2018-08-29 22:54:12 -0700
committerStan Hu <stanhu@gmail.com>2018-08-29 22:54:12 -0700
commit69eddc14b11b63429b8f2511a1127616c692b94c (patch)
treea94482be144cef60a8ee1b590857ca24f49f418a
parentbc7a4eedf9fa6681465b622af52c34d49ffb5d0e (diff)
parentf981d4febbbb5103262f4daa858236d9c4ed9d67 (diff)
downloadgitlab-ce-69eddc14b11b63429b8f2511a1127616c692b94c.tar.gz
Merge branch 'master' into sh-test-ldap-clones-via-gitlab-qa
-rw-r--r--.flayignore1
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.gitlab/issue_templates/Test plan.md96
-rw-r--r--.haml-lint.yml53
-rw-r--r--CHANGELOG.md55
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Gemfile.rails5.lock18
-rw-r--r--app/assets/javascripts/awards_handler.js33
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js8
-rw-r--r--app/assets/javascripts/jobs/components/environments_block.vue118
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue24
-rw-r--r--app/assets/javascripts/pages/groups/milestones/show/index.js4
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue6
-rw-r--r--app/assets/javascripts/pages/profiles/show/index.js32
-rw-r--r--app/assets/javascripts/performance_bar/index.js4
-rw-r--r--app/assets/javascripts/performance_bar/services/performance_bar_service.js21
-rw-r--r--app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue3
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_component.vue5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue61
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue67
-rw-r--r--app/assets/stylesheets/framework/callout.scss24
-rw-r--r--app/assets/stylesheets/framework/common.scss10
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss8
-rw-r--r--app/assets/stylesheets/framework/emojis.scss4
-rw-r--r--app/assets/stylesheets/framework/feature_highlight.scss4
-rw-r--r--app/assets/stylesheets/framework/files.scss4
-rw-r--r--app/assets/stylesheets/framework/forms.scss2
-rw-r--r--app/assets/stylesheets/framework/selects.scss6
-rw-r--r--app/assets/stylesheets/framework/variables.scss63
-rw-r--r--app/assets/stylesheets/pages/builds.scss2
-rw-r--r--app/assets/stylesheets/pages/convdev_index.scss12
-rw-r--r--app/assets/stylesheets/pages/editor.scss4
-rw-r--r--app/assets/stylesheets/pages/environments.scss2
-rw-r--r--app/assets/stylesheets/pages/login.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss39
-rw-r--r--app/assets/stylesheets/pages/notes.scss3
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss10
-rw-r--r--app/assets/stylesheets/pages/projects.scss6
-rw-r--r--app/assets/stylesheets/pages/runners.scss10
-rw-r--r--app/assets/stylesheets/pages/stat_graph.scss4
-rw-r--r--app/controllers/concerns/renders_commits.rb20
-rw-r--r--app/controllers/concerns/toggle_award_emoji.rb2
-rw-r--r--app/controllers/groups/milestones_controller.rb17
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/compare_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/helpers/commits_helper.rb11
-rw-r--r--app/helpers/import_helper.rb4
-rw-r--r--app/helpers/issues_helper.rb8
-rw-r--r--app/helpers/projects_helper.rb6
-rw-r--r--app/models/ci/pipeline.rb3
-rw-r--r--app/models/concerns/awardable.rb16
-rw-r--r--app/models/diff_note.rb16
-rw-r--r--app/models/issue.rb47
-rw-r--r--app/models/merge_request_diff.rb4
-rw-r--r--app/models/project.rb16
-rw-r--r--app/models/protected_tag.rb2
-rw-r--r--app/models/remote_mirror.rb9
-rw-r--r--app/models/repository.rb21
-rw-r--r--app/policies/group_policy.rb4
-rw-r--r--app/policies/project_policy.rb4
-rw-r--r--app/services/git_push_service.rb14
-rw-r--r--app/services/groups/destroy_service.rb5
-rw-r--r--app/services/issues/fetch_referenced_merge_requests_service.rb14
-rw-r--r--app/services/issues/referenced_merge_requests_service.rb66
-rw-r--r--app/services/merge_requests/build_service.rb19
-rw-r--r--app/services/milestones/destroy_service.rb20
-rw-r--r--app/services/projects/update_remote_mirror_service.rb1
-rw-r--r--app/services/quick_actions/interpret_service.rb2
-rw-r--r--app/views/admin/hook_logs/show.html.haml3
-rw-r--r--app/views/admin/users/show.html.haml4
-rw-r--r--app/views/award_emoji/_awards_block.html.haml3
-rw-r--r--app/views/ci/runner/_how_to_setup_runner.html.haml2
-rw-r--r--app/views/ci/status/_dropdown_graph_badge.html.haml4
-rw-r--r--app/views/groups/milestones/index.html.haml2
-rw-r--r--app/views/import/_githubish_status.html.haml2
-rw-r--r--app/views/import/bitbucket/status.html.haml2
-rw-r--r--app/views/import/bitbucket_server/status.html.haml2
-rw-r--r--app/views/projects/_issuable_by_email.html.haml11
-rw-r--r--app/views/projects/commits/_commit_list.html.haml5
-rw-r--r--app/views/projects/commits/_commits.html.haml3
-rw-r--r--app/views/projects/diffs/_line.html.haml4
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml4
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/hook_logs/show.html.haml2
-rw-r--r--app/views/projects/jobs/_sidebar.html.haml2
-rw-r--r--app/views/projects/merge_requests/_how_to_merge.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/_new_submit.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml13
-rw-r--r--app/views/projects/mirrors/_instructions.html.haml4
-rw-r--r--app/views/projects/notes/_actions.html.haml2
-rw-r--r--app/views/shared/milestones/_delete_button.html.haml14
-rw-r--r--app/views/shared/milestones/_milestone.html.haml5
-rw-r--r--app/views/shared/milestones/_top.html.haml5
-rw-r--r--app/views/snippets/notes/_actions.html.haml2
-rw-r--r--changelogs/unreleased/43096-controller-projects-issuescontroller-referenced_merge_requests-json-executes-more-than-100-sql-queries.yml5
-rw-r--r--changelogs/unreleased/43625-increase-modal-checkout.yml5
-rw-r--r--changelogs/unreleased/49110-update-mr-widget-styles.yml5
-rw-r--r--changelogs/unreleased/49292-add-group-name-badge-under-milestone.yml5
-rw-r--r--changelogs/unreleased/50101-env-block.yml5
-rw-r--r--changelogs/unreleased/50345-hashed-storage-feature-flag.yml5
-rw-r--r--changelogs/unreleased/50441-high-number-of-statement-timeouts-in-groupdestroyworker-due-to-sitestatistics.yml5
-rw-r--r--changelogs/unreleased/50584-fix-ide-commit-twice.yml5
-rw-r--r--changelogs/unreleased/50801-error-getting-performance-bar-results-for-uuid.yml5
-rw-r--r--changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml6
-rw-r--r--changelogs/unreleased/api-protected-tags.yml5
-rw-r--r--changelogs/unreleased/bvl-add-galician.yml5
-rw-r--r--changelogs/unreleased/ccr-43283_allow_author_upvote.yml5
-rw-r--r--changelogs/unreleased/ccr-48800-ping_for_boards.yml6
-rw-r--r--changelogs/unreleased/expose-users-id-in-admin-users-show-page.yml5
-rw-r--r--changelogs/unreleased/fix-api-group-createdat.yml5
-rw-r--r--changelogs/unreleased/fix-mr-title-fallback-logic.yml5
-rw-r--r--changelogs/unreleased/fix_emojis_cutting_and_regressions.yml5
-rw-r--r--changelogs/unreleased/issue_36138.yml5
-rw-r--r--changelogs/unreleased/jprovazn-fix-form-uploads.yml5
-rw-r--r--changelogs/unreleased/rails5-fix-import-merge-request-creator.yml5
-rw-r--r--changelogs/unreleased/rails5-silence-stream.yml5
-rw-r--r--changelogs/unreleased/rails5-update-gemfile-lock.yml5
-rw-r--r--changelogs/unreleased/security-49085-persistent-xss-rendering.yml5
-rw-r--r--changelogs/unreleased/sh-block-link-local-master.yml5
-rw-r--r--changelogs/unreleased/sh-conditional-system-hook-push.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-50562.yml5
-rw-r--r--changelogs/unreleased/sh-insert-git-data-in-separate-transaction.yml5
-rw-r--r--changelogs/unreleased/sh-limit-commit-renderering.yml5
-rw-r--r--changelogs/unreleased/sh-sanitize-project-import-names.yml5
-rw-r--r--changelogs/unreleased/winh-default-status-emoji.yml5
-rw-r--r--config/routes/admin.rb2
-rw-r--r--config/routes/group.rb2
-rw-r--r--config/routes/project.rb2
-rw-r--r--danger/changelog/Dangerfile6
-rw-r--r--db/migrate/20180711103851_drop_duplicate_protected_tags.rb45
-rw-r--r--db/migrate/20180711103922_add_protected_tags_index.rb18
-rw-r--r--db/migrate/20180815175440_add_index_on_list_type.rb16
-rw-r--r--db/post_migrate/20180826111825_recalculate_site_statistics.rb27
-rw-r--r--db/schema.rb4
-rw-r--r--doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.pngbin27877 -> 11991 bytes
-rw-r--r--doc/administration/auth/img/crowd_application.pngbin55811 -> 17172 bytes
-rw-r--r--doc/administration/auth/img/crowd_application_authorisation.pngbin126994 -> 37026 bytes
-rw-r--r--doc/administration/img/circuitbreaker_config.pngbin99523 -> 29130 bytes
-rw-r--r--doc/administration/img/custom_hooks_error_msg.pngbin44922 -> 44892 bytes
-rw-r--r--doc/administration/img/failing_storage.pngbin48281 -> 16291 bytes
-rw-r--r--doc/administration/img/integration/plantuml-example.pngbin33034 -> 12559 bytes
-rw-r--r--doc/administration/img/repository_storages_admin_ui.pngbin70416 -> 20439 bytes
-rw-r--r--doc/administration/monitoring/performance/img/grafana_dashboard_import.pngbin11836 -> 11835 bytes
-rw-r--r--doc/administration/monitoring/performance/img/grafana_data_source_configuration.pngbin14700 -> 14695 bytes
-rw-r--r--doc/administration/monitoring/performance/img/grafana_data_source_empty.pngbin11963 -> 11960 bytes
-rw-r--r--doc/administration/monitoring/performance/img/grafana_save_icon.pngbin4619 -> 4598 bytes
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar.pngbin344274 -> 99331 bytes
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar_configuration_settings.pngbin20385 -> 16455 bytes
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.pngbin278693 -> 91275 bytes
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar_line_profiling.pngbin161313 -> 93063 bytes
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar_sql_queries.pngbin165124 -> 128337 bytes
-rw-r--r--doc/administration/monitoring/performance/img/request_profile_result.pngbin3236 -> 3216 bytes
-rw-r--r--doc/administration/monitoring/performance/img/request_profiling_token.pngbin10229 -> 10217 bytes
-rw-r--r--doc/administration/operations/img/sidekiq_job_throttling.pngbin32229 -> 32224 bytes
-rw-r--r--doc/administration/operations/img/write_to_authorized_keys_setting.pngbin94218 -> 29192 bytes
-rw-r--r--doc/api/README.md1
-rw-r--r--doc/api/discussions.md16
-rw-r--r--doc/api/group_milestones.md13
-rw-r--r--doc/api/issues.md2
-rw-r--r--doc/api/notes.md2
-rw-r--r--doc/api/protected_tags.md128
-rw-r--r--doc/ci/autodeploy/img/auto_deploy_btn.pngbin46825 -> 16779 bytes
-rw-r--r--doc/ci/autodeploy/img/auto_deploy_button.pngbin43441 -> 13321 bytes
-rw-r--r--doc/ci/autodeploy/img/auto_deploy_dropdown.pngbin75456 -> 28357 bytes
-rw-r--r--doc/ci/autodeploy/img/auto_monitoring.pngbin89206 -> 56765 bytes
-rw-r--r--doc/ci/autodeploy/img/guide_connect_cluster.pngbin38724 -> 15225 bytes
-rw-r--r--doc/ci/autodeploy/img/guide_integration.pngbin44263 -> 15042 bytes
-rw-r--r--doc/ci/autodeploy/img/guide_secret.pngbin16233 -> 4803 bytes
-rw-r--r--doc/ci/caching/img/clear_runners_cache.pngbin16029 -> 16020 bytes
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.pngbin22046 -> 9300 bytes
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.pngbin27620 -> 15160 bytes
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.pngbin18789 -> 9985 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.pngbin56091 -> 23936 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.pngbin339666 -> 105954 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.pngbin185393 -> 79265 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.pngbin134742 -> 56126 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.pngbin172664 -> 70582 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.pngbin119955 -> 50117 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.pngbin141393 -> 59140 bytes
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.pngbin233764 -> 96864 bytes
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/job-succeeded.pngbin62101 -> 23148 bytes
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.pngbin16112 -> 6602 bytes
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.pngbin73726 -> 25235 bytes
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.pngbin40381 -> 15794 bytes
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select-template.pngbin29968 -> 12345 bytes
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/setup-ci.pngbin46405 -> 19183 bytes
-rw-r--r--doc/ci/img/deployments_view.pngbin61088 -> 23352 bytes
-rw-r--r--doc/ci/img/environments_available.pngbin21089 -> 8464 bytes
-rw-r--r--doc/ci/img/environments_dynamic_groups.pngbin58239 -> 21902 bytes
-rw-r--r--doc/ci/img/environments_link_url_mr.pngbin34361 -> 14346 bytes
-rw-r--r--doc/ci/img/environments_manual_action_deployments.pngbin32748 -> 12635 bytes
-rw-r--r--doc/ci/img/environments_manual_action_environments.pngbin24191 -> 9485 bytes
-rw-r--r--doc/ci/img/environments_manual_action_jobs.pngbin19919 -> 8446 bytes
-rw-r--r--doc/ci/img/environments_manual_action_pipelines.pngbin38974 -> 14979 bytes
-rw-r--r--doc/ci/img/environments_manual_action_single_pipeline.pngbin23381 -> 10273 bytes
-rw-r--r--doc/ci/img/environments_monitoring.pngbin76086 -> 45153 bytes
-rw-r--r--doc/ci/img/environments_mr_review_app.pngbin30991 -> 13394 bytes
-rw-r--r--doc/ci/img/environments_terminal_button_on_index.pngbin29162 -> 11080 bytes
-rw-r--r--doc/ci/img/environments_terminal_button_on_show.pngbin17811 -> 7642 bytes
-rw-r--r--doc/ci/img/environments_terminal_page.pngbin117863 -> 28166 bytes
-rw-r--r--doc/ci/img/job_failure_reason.pngbin5346 -> 5288 bytes
-rw-r--r--doc/ci/img/pipelines_grouped.pngbin12937 -> 12888 bytes
-rw-r--r--doc/ci/img/pipelines_index.pngbin36299 -> 14896 bytes
-rw-r--r--doc/ci/img/pipelines_mini_graph.pngbin15404 -> 4671 bytes
-rw-r--r--doc/ci/img/pipelines_mini_graph_simple.pngbin1637 -> 961 bytes
-rw-r--r--doc/ci/img/view_on_env_blob.pngbin111663 -> 32924 bytes
-rw-r--r--doc/ci/img/view_on_env_mr.pngbin1005195 -> 295181 bytes
-rw-r--r--doc/ci/interactive_web_terminal/img/interactive_web_terminal_page.pngbin23431 -> 23364 bytes
-rw-r--r--doc/ci/interactive_web_terminal/img/interactive_web_terminal_running_job.pngbin55682 -> 55677 bytes
-rw-r--r--doc/ci/quick_start/img/build_log.pngbin35261 -> 35256 bytes
-rw-r--r--doc/ci/quick_start/img/builds_status.pngbin19127 -> 19107 bytes
-rw-r--r--doc/ci/quick_start/img/new_commit.pngbin5584 -> 5541 bytes
-rw-r--r--doc/ci/review_apps/img/review_apps_preview_in_mr.pngbin11723 -> 11664 bytes
-rw-r--r--doc/ci/runners/img/protected_runners_check_box.pngbin8584 -> 3963 bytes
-rw-r--r--doc/ci/runners/img/shared_runner_ip_address.pngbin69821 -> 20276 bytes
-rw-r--r--doc/ci/runners/img/specific_runner_ip_address.pngbin42055 -> 12209 bytes
-rw-r--r--doc/ci/triggers/img/builds_page.pngbin20383 -> 20366 bytes
-rw-r--r--doc/ci/triggers/img/trigger_single_build.pngbin6585 -> 6584 bytes
-rw-r--r--doc/customization/branded_login_page/custom_sign_in.pngbin79288 -> 79276 bytes
-rw-r--r--doc/customization/branded_page_and_email_header/appearance.pngbin10253 -> 5625 bytes
-rw-r--r--doc/customization/branded_page_and_email_header/custom_brand_header.pngbin10014 -> 5279 bytes
-rw-r--r--doc/customization/branded_page_and_email_header/custom_email_header.pngbin37472 -> 14671 bytes
-rw-r--r--doc/customization/favicon/appearance.pngbin52245 -> 28933 bytes
-rw-r--r--doc/customization/favicon/custom_favicon.pngbin60083 -> 31600 bytes
-rw-r--r--doc/customization/new_project_page/appearance_settings.pngbin71178 -> 30473 bytes
-rw-r--r--doc/customization/new_project_page/custom_new_project_page.pngbin164962 -> 69523 bytes
-rw-r--r--doc/customization/new_project_page/default_new_project_page.pngbin146906 -> 62717 bytes
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/architecture.md2
-rw-r--r--doc/development/documentation/img/manual_build_docs.pngbin14867 -> 14855 bytes
-rw-r--r--doc/development/fe_guide/img/boards_diagram.pngbin30538 -> 9518 bytes
-rw-r--r--doc/development/fe_guide/img/gl-modal.pngbin25893 -> 8767 bytes
-rw-r--r--doc/development/feature_flags.md12
-rw-r--r--doc/development/gitlab_architecture_diagram.pngbin61667 -> 34253 bytes
-rw-r--r--doc/development/img/trigger_ss1.pngbin106261 -> 35756 bytes
-rw-r--r--doc/development/img/trigger_ss2.pngbin106671 -> 36082 bytes
-rw-r--r--doc/development/ux_guide/img/button-close--active.pngbin1385 -> 1120 bytes
-rw-r--r--doc/development/ux_guide/img/button-close--hover.pngbin1015 -> 765 bytes
-rw-r--r--doc/development/ux_guide/img/button-close--resting.pngbin1271 -> 915 bytes
-rw-r--r--doc/development/ux_guide/img/button-danger--active.pngbin1450 -> 1117 bytes
-rw-r--r--doc/development/ux_guide/img/button-danger--hover.pngbin1095 -> 797 bytes
-rw-r--r--doc/development/ux_guide/img/button-danger--resting.pngbin1376 -> 932 bytes
-rw-r--r--doc/development/ux_guide/img/button-info--active.pngbin1442 -> 1109 bytes
-rw-r--r--doc/development/ux_guide/img/button-info--hover.pngbin1079 -> 795 bytes
-rw-r--r--doc/development/ux_guide/img/button-info--resting.pngbin1296 -> 930 bytes
-rw-r--r--doc/development/ux_guide/img/button-spam--active.pngbin1435 -> 1107 bytes
-rw-r--r--doc/development/ux_guide/img/button-spam--hover.pngbin1108 -> 777 bytes
-rw-r--r--doc/development/ux_guide/img/button-spam--resting.pngbin1377 -> 941 bytes
-rw-r--r--doc/development/ux_guide/img/button-success--active.pngbin1510 -> 1153 bytes
-rw-r--r--doc/development/ux_guide/img/button-success--hover.pngbin1151 -> 892 bytes
-rw-r--r--doc/development/ux_guide/img/button-success--resting.pngbin1447 -> 1045 bytes
-rw-r--r--doc/development/ux_guide/img/button-success-secondary--active.pngbin1466 -> 1107 bytes
-rw-r--r--doc/development/ux_guide/img/button-success-secondary--hover.pngbin1091 -> 774 bytes
-rw-r--r--doc/development/ux_guide/img/button-success-secondary--resting.pngbin1394 -> 945 bytes
-rw-r--r--doc/development/ux_guide/img/button-warning--active.pngbin1388 -> 1124 bytes
-rw-r--r--doc/development/ux_guide/img/button-warning--hover.pngbin1040 -> 790 bytes
-rw-r--r--doc/development/ux_guide/img/button-warning--resting.pngbin1296 -> 925 bytes
-rw-r--r--doc/development/ux_guide/img/color-blue.pngbin3555 -> 1751 bytes
-rw-r--r--doc/development/ux_guide/img/color-green.pngbin3852 -> 1916 bytes
-rw-r--r--doc/development/ux_guide/img/color-grey.pngbin3523 -> 1681 bytes
-rw-r--r--doc/development/ux_guide/img/color-orange.pngbin4480 -> 2094 bytes
-rw-r--r--doc/development/ux_guide/img/color-red.pngbin3550 -> 1739 bytes
-rw-r--r--doc/development/ux_guide/img/components-anchorlinks.pngbin30089 -> 16457 bytes
-rw-r--r--doc/development/ux_guide/img/components-coverblock.pngbin10141 -> 10110 bytes
-rw-r--r--doc/development/ux_guide/img/components-dateexact.pngbin4161 -> 4157 bytes
-rw-r--r--doc/development/ux_guide/img/components-fileholder.pngbin3938 -> 3884 bytes
-rw-r--r--doc/development/ux_guide/img/components-horizontalform.pngbin4327 -> 4310 bytes
-rw-r--r--doc/development/ux_guide/img/components-listinsidepanel.pngbin3449 -> 3380 bytes
-rw-r--r--doc/development/ux_guide/img/components-listwithhover.pngbin2860 -> 2722 bytes
-rw-r--r--doc/development/ux_guide/img/components-referencehover.pngbin6948 -> 6890 bytes
-rw-r--r--doc/development/ux_guide/img/components-referenceissues.pngbin10009 -> 10002 bytes
-rw-r--r--doc/development/ux_guide/img/components-referencelabels.pngbin4108 -> 4099 bytes
-rw-r--r--doc/development/ux_guide/img/components-referencemilestone.pngbin2417 -> 2412 bytes
-rw-r--r--doc/development/ux_guide/img/components-referencemrs.pngbin8859 -> 8857 bytes
-rw-r--r--doc/development/ux_guide/img/components-referencepeople.pngbin5607 -> 5600 bytes
-rw-r--r--doc/development/ux_guide/img/components-searchbox.pngbin5292 -> 3596 bytes
-rw-r--r--doc/development/ux_guide/img/components-searchboxscoped.pngbin9668 -> 6027 bytes
-rw-r--r--doc/development/ux_guide/img/components-simplelist.pngbin2781 -> 2776 bytes
-rw-r--r--doc/development/ux_guide/img/features-contextualnav.pngbin5912 -> 5911 bytes
-rw-r--r--doc/development/ux_guide/img/features-emptystates.pngbin61664 -> 61644 bytes
-rw-r--r--doc/development/ux_guide/img/icon-add.pngbin317 -> 239 bytes
-rw-r--r--doc/development/ux_guide/img/icon-close.pngbin501 -> 301 bytes
-rw-r--r--doc/development/ux_guide/img/icon-edit.pngbin546 -> 315 bytes
-rw-r--r--doc/development/ux_guide/img/icon-notification.pngbin543 -> 379 bytes
-rw-r--r--doc/development/ux_guide/img/icon-rss.pngbin834 -> 528 bytes
-rw-r--r--doc/development/ux_guide/img/icon-spec.pngbin13889 -> 7523 bytes
-rw-r--r--doc/development/ux_guide/img/icon-subscribe.pngbin760 -> 537 bytes
-rw-r--r--doc/development/ux_guide/img/icon-trash.pngbin398 -> 281 bytes
-rw-r--r--doc/development/ux_guide/img/illustrations-caps-do.pngbin3775 -> 3671 bytes
-rw-r--r--doc/development/ux_guide/img/illustrations-caps-don't.pngbin3922 -> 3624 bytes
-rw-r--r--doc/development/ux_guide/img/james-mackey.pngbin32552 -> 11869 bytes
-rw-r--r--doc/development/ux_guide/img/karolina-plaskaty.pngbin29553 -> 10355 bytes
-rw-r--r--doc/development/ux_guide/img/matthieu-poirier.pngbin32819 -> 11483 bytes
-rw-r--r--doc/development/ux_guide/img/modals-general-confimation-dialog.pngbin51205 -> 15650 bytes
-rw-r--r--doc/development/ux_guide/img/modals-layout-for-modals.pngbin68203 -> 20060 bytes
-rw-r--r--doc/development/ux_guide/img/modals-special-confimation-dialog.pngbin89978 -> 31419 bytes
-rw-r--r--doc/development/ux_guide/img/modals-three-buttons.pngbin54927 -> 17457 bytes
-rw-r--r--doc/development/ux_guide/img/nazim-ramesh.pngbin27475 -> 10488 bytes
-rw-r--r--doc/development/ux_guide/img/popover-placement-above.pngbin68451 -> 20184 bytes
-rw-r--r--doc/development/ux_guide/img/popover-placement-below.pngbin63368 -> 19967 bytes
-rw-r--r--doc/development/ux_guide/img/surfaces-contentitemtitle.pngbin5142 -> 5139 bytes
-rw-r--r--doc/development/ux_guide/img/surfaces-systeminformationblock.pngbin10423 -> 10422 bytes
-rw-r--r--doc/development/ux_guide/img/surfaces-ux.pngbin4029 -> 4017 bytes
-rw-r--r--doc/development/ux_guide/img/tooltip-placement.pngbin2071 -> 2066 bytes
-rw-r--r--doc/development/ux_guide/img/tooltip-usage.pngbin5994 -> 5985 bytes
-rw-r--r--doc/gitlab-basics/img/create_new_project_info.pngbin77490 -> 71608 bytes
-rw-r--r--doc/gitlab-basics/img/fork_new.pngbin10722 -> 10572 bytes
-rw-r--r--doc/gitlab-basics/img/merge_request_select_branch.pngbin16668 -> 16654 bytes
-rw-r--r--doc/gitlab-basics/img/profile_settings.pngbin5842 -> 2842 bytes
-rw-r--r--doc/gitlab-basics/img/profile_settings_ssh_keys_paste_pub.pngbin13447 -> 13436 bytes
-rw-r--r--doc/gitlab-basics/img/profile_settings_ssh_keys_single_key.pngbin24639 -> 10534 bytes
-rw-r--r--doc/gitlab-basics/img/profile_settings_ssh_keys_title.pngbin1872 -> 1867 bytes
-rw-r--r--doc/img/devops_lifecycle.pngbin65043 -> 18611 bytes
-rw-r--r--doc/install/google_cloud_platform/img/boot_disk.pngbin124175 -> 37786 bytes
-rw-r--r--doc/install/google_cloud_platform/img/first_signin.pngbin69516 -> 48215 bytes
-rw-r--r--doc/install/google_cloud_platform/img/gcp_landing.pngbin15025 -> 9978 bytes
-rw-r--r--doc/install/google_cloud_platform/img/launch_vm.pngbin47201 -> 33906 bytes
-rw-r--r--doc/install/google_cloud_platform/img/ssh_terminal.pngbin94161 -> 59212 bytes
-rw-r--r--doc/install/google_cloud_platform/img/vm_created.pngbin13809 -> 9903 bytes
-rw-r--r--doc/install/google_cloud_platform/img/vm_details.pngbin76519 -> 50191 bytes
-rw-r--r--doc/install/installation.md48
-rw-r--r--doc/install/kubernetes/gitlab_chart.md2
-rw-r--r--doc/install/openshift_and_gitlab/img/add-gitlab-to-project.pngbin37386 -> 14619 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/add-to-project.pngbin21672 -> 8901 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/create-project-ui.pngbin22290 -> 9151 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/gitlab-logs.pngbin70858 -> 26240 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/gitlab-overview.pngbin106432 -> 42908 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/gitlab-running.pngbin107993 -> 42045 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/gitlab-scale.pngbin36628 -> 15002 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/gitlab-settings.pngbin111366 -> 42221 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/no-resources.pngbin34669 -> 12465 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/openshift-infra-project.pngbin95725 -> 37117 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/pods-overview.pngbin106861 -> 42617 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/rc-name.pngbin51390 -> 20571 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/running-pods.pngbin29818 -> 11942 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/storage-volumes.pngbin49584 -> 20007 bytes
-rw-r--r--doc/install/openshift_and_gitlab/img/web-console.pngbin34774 -> 12717 bytes
-rw-r--r--doc/integration/img/bitbucket_oauth_keys.pngbin5149 -> 5146 bytes
-rw-r--r--doc/integration/img/enable_trello_powerup.pngbin17905 -> 17791 bytes
-rw-r--r--doc/integration/img/enabled-oauth-sign-in-sources.pngbin13304 -> 13303 bytes
-rw-r--r--doc/integration/img/facebook_api_keys.pngbin42308 -> 42290 bytes
-rw-r--r--doc/integration/img/facebook_website_url.pngbin9620 -> 9615 bytes
-rw-r--r--doc/integration/img/gitlab_app.pngbin56480 -> 32020 bytes
-rw-r--r--doc/integration/img/google_app.pngbin19168 -> 18853 bytes
-rw-r--r--doc/integration/img/oauth_provider_admin_application.pngbin17082 -> 17071 bytes
-rw-r--r--doc/integration/img/oauth_provider_application_form.pngbin12566 -> 12553 bytes
-rw-r--r--doc/integration/img/oauth_provider_application_id_secret.pngbin15293 -> 15280 bytes
-rw-r--r--doc/integration/img/oauth_provider_authorized_application.pngbin14668 -> 14657 bytes
-rw-r--r--doc/integration/img/submit_issue.pngbin45962 -> 45771 bytes
-rw-r--r--doc/integration/img/twitter_app_api_keys.pngbin24577 -> 24570 bytes
-rw-r--r--doc/monitoring/performance/img/grafana_dashboard_import.pngbin11836 -> 11835 bytes
-rw-r--r--doc/monitoring/performance/img/grafana_data_source_configuration.pngbin14700 -> 14695 bytes
-rw-r--r--doc/monitoring/performance/img/grafana_data_source_empty.pngbin11963 -> 11960 bytes
-rw-r--r--doc/monitoring/performance/img/grafana_save_icon.pngbin4619 -> 4598 bytes
-rw-r--r--doc/monitoring/performance/img/metrics_gitlab_configuration_settings.pngbin21387 -> 21382 bytes
-rw-r--r--doc/public_access/img/restrict_visibility_levels.pngbin24593 -> 18825 bytes
-rw-r--r--doc/raketasks/backup_hrz.pngbin11444 -> 11441 bytes
-rw-r--r--doc/security/img/outbound_requests_section.pngbin18064 -> 7314 bytes
-rw-r--r--doc/security/img/ssh_keys_restrictions_settings.pngbin68496 -> 19571 bytes
-rw-r--r--doc/security/img/two_factor_authentication_group_settings.pngbin44874 -> 19495 bytes
-rw-r--r--doc/security/img/two_factor_authentication_settings.pngbin9941 -> 9936 bytes
-rw-r--r--doc/topics/autodevops/img/guide_environments.pngbin8570 -> 8434 bytes
-rw-r--r--doc/topics/autodevops/img/guide_ide_commit.pngbin22035 -> 22029 bytes
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/img/branching.pngbin26245 -> 12744 bytes
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/img/rebase_reset.pngbin43609 -> 21836 bytes
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/img/revert.pngbin28112 -> 13243 bytes
-rw-r--r--doc/university/high-availability/aws/img/auto-scaling-det.pngbin29970 -> 29967 bytes
-rw-r--r--doc/university/high-availability/aws/img/db-subnet-group.pngbin29306 -> 29298 bytes
-rw-r--r--doc/university/high-availability/aws/img/ig.pngbin8149 -> 8140 bytes
-rw-r--r--doc/university/high-availability/aws/img/instance_specs.pngbin11525 -> 11522 bytes
-rw-r--r--doc/university/high-availability/aws/img/new_vpc.pngbin15696 -> 15691 bytes
-rw-r--r--doc/university/high-availability/aws/img/policies.pngbin39845 -> 39723 bytes
-rw-r--r--doc/university/high-availability/aws/img/rds-net-opt.pngbin16347 -> 16340 bytes
-rw-r--r--doc/university/high-availability/aws/img/rds-sec-group.pngbin11584 -> 11579 bytes
-rw-r--r--doc/university/high-availability/aws/img/subnet.pngbin17077 -> 17070 bytes
-rw-r--r--doc/university/training/gitlab_flow/production_branch.pngbin7293 -> 7291 bytes
-rw-r--r--doc/university/training/gitlab_flow/release_branches.pngbin12775 -> 12765 bytes
-rw-r--r--doc/update/10.7-to-10.8.md20
-rw-r--r--doc/user/admin_area/monitoring/img/health_check_token.pngbin4923 -> 4863 bytes
-rw-r--r--doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.pngbin14656 -> 5360 bytes
-rw-r--r--doc/user/admin_area/settings/img/admin_area_maximum_artifacts_size.pngbin12917 -> 4771 bytes
-rw-r--r--doc/user/admin_area/settings/img/domain_blacklist.pngbin13606 -> 13601 bytes
-rw-r--r--doc/user/admin_area/settings/img/restricted_url.pngbin18202 -> 18191 bytes
-rw-r--r--doc/user/admin_area/settings/img/update-available.pngbin89748 -> 26769 bytes
-rw-r--r--doc/user/discussions/img/automatically_resolve_outdated_discussions.pngbin117604 -> 38001 bytes
-rw-r--r--doc/user/discussions/img/btn_new_issue_for_all_discussions.pngbin29007 -> 9555 bytes
-rw-r--r--doc/user/discussions/img/discussion_comment.pngbin57189 -> 37351 bytes
-rw-r--r--doc/user/discussions/img/discussion_lock_system_notes.pngbin50200 -> 14288 bytes
-rw-r--r--doc/user/discussions/img/discussion_view.pngbin73821 -> 73807 bytes
-rw-r--r--doc/user/discussions/img/lock_form_member.pngbin100581 -> 23780 bytes
-rw-r--r--doc/user/discussions/img/lock_form_non_member.pngbin37432 -> 8362 bytes
-rw-r--r--doc/user/discussions/img/new_issue_for_discussion.pngbin39563 -> 11324 bytes
-rw-r--r--doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.pngbin4962 -> 4944 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_discussion.pngbin82412 -> 26965 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_discussions.pngbin143871 -> 35211 bytes
-rw-r--r--doc/user/discussions/img/resolve_comment_button.pngbin4722 -> 4713 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_issue_notice.pngbin10307 -> 4186 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_open_issue.pngbin20967 -> 7514 bytes
-rw-r--r--doc/user/discussions/img/turn_off_lock.pngbin31580 -> 9626 bytes
-rw-r--r--doc/user/discussions/img/turn_on_lock.pngbin34839 -> 10409 bytes
-rw-r--r--doc/user/group/img/add_new_members.pngbin67235 -> 18048 bytes
-rw-r--r--doc/user/group/img/create_new_group_info.pngbin105173 -> 30175 bytes
-rw-r--r--doc/user/group/img/create_new_project_from_group.pngbin3194 -> 3185 bytes
-rw-r--r--doc/user/group/img/group_settings.pngbin28821 -> 9704 bytes
-rw-r--r--doc/user/group/img/groups.pngbin249533 -> 62070 bytes
-rw-r--r--doc/user/group/img/membership_lock.pngbin17333 -> 4820 bytes
-rw-r--r--doc/user/group/img/new_group_form.pngbin114515 -> 32510 bytes
-rw-r--r--doc/user/group/img/new_group_from_groups.pngbin109302 -> 25256 bytes
-rw-r--r--doc/user/group/img/new_group_from_other_pages.pngbin90423 -> 21593 bytes
-rw-r--r--doc/user/group/img/request_access_button.pngbin35917 -> 35908 bytes
-rw-r--r--doc/user/group/img/select_group_dropdown.pngbin3489 -> 3482 bytes
-rw-r--r--doc/user/group/img/share_with_group_lock.pngbin21541 -> 7493 bytes
-rw-r--r--doc/user/group/img/withdraw_access_request_button.pngbin36413 -> 36393 bytes
-rw-r--r--doc/user/group/subgroups/img/group_members.pngbin48240 -> 18009 bytes
-rw-r--r--doc/user/group/subgroups/img/mention_subgroups.pngbin39666 -> 14783 bytes
-rw-r--r--doc/user/img/award_emoji_comment_picker.pngbin72883 -> 72847 bytes
-rw-r--r--doc/user/img/award_emoji_select.pngbin17827 -> 17554 bytes
-rw-r--r--doc/user/img/award_emoji_votes_sort_options.pngbin99941 -> 40489 bytes
-rw-r--r--doc/user/img/markdown_logo.pngbin4421 -> 4398 bytes
-rw-r--r--doc/user/instance_statistics/img/convdev_index.pngbin316893 -> 86358 bytes
-rw-r--r--doc/user/profile/img/active_sessions_list.pngbin41649 -> 22266 bytes
-rw-r--r--doc/user/profile/img/personal_access_tokens.pngbin18555 -> 18553 bytes
-rw-r--r--doc/user/profile/img/profil-preferences-navigation-theme.pngbin16403 -> 16397 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/add_cluster.pngbin77046 -> 59516 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/create_dns.pngbin29185 -> 23923 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/create_project.pngbin43429 -> 30568 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.pngbin115299 -> 82157 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/environment.pngbin31644 -> 20339 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/new_project.pngbin10309 -> 7813 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/pipeline.pngbin26500 -> 15288 bytes
-rw-r--r--doc/user/project/deploy_tokens/img/deploy_tokens.pngbin75650 -> 23087 bytes
-rw-r--r--doc/user/project/img/bulk-editing.pngbin197686 -> 197667 bytes
-rw-r--r--doc/user/project/img/cycle_analytics_landing_page.pngbin42117 -> 42114 bytes
-rw-r--r--doc/user/project/img/issue_board_assignee_lists.pngbin134674 -> 134635 bytes
-rw-r--r--doc/user/project/img/issue_board_creation.pngbin108674 -> 108615 bytes
-rw-r--r--doc/user/project/img/issue_board_edit_button.pngbin108168 -> 108114 bytes
-rw-r--r--doc/user/project/img/issue_board_move_issue_card_list.pngbin13670 -> 13592 bytes
-rw-r--r--doc/user/project/img/issue_board_view_scope.pngbin63542 -> 63529 bytes
-rw-r--r--doc/user/project/img/issue_boards_add_issues_modal.pngbin12421 -> 12415 bytes
-rw-r--r--doc/user/project/img/issue_boards_multiple.pngbin6092 -> 6086 bytes
-rw-r--r--doc/user/project/img/issue_boards_remove_issue.pngbin39357 -> 39347 bytes
-rw-r--r--doc/user/project/img/koding_build-in-progress.pngbin21953 -> 21937 bytes
-rw-r--r--doc/user/project/img/koding_build-success.pngbin73008 -> 73005 bytes
-rw-r--r--doc/user/project/img/koding_commit-koding.yml.pngbin86043 -> 86023 bytes
-rw-r--r--doc/user/project/img/koding_edit-on-ide.pngbin90701 -> 90638 bytes
-rw-r--r--doc/user/project/img/koding_enable-koding.pngbin20303 -> 20291 bytes
-rw-r--r--doc/user/project/img/koding_landing.pngbin81010 -> 80985 bytes
-rw-r--r--doc/user/project/img/koding_run-in-ide.pngbin22179 -> 22178 bytes
-rw-r--r--doc/user/project/img/koding_stack-import.pngbin137608 -> 137582 bytes
-rw-r--r--doc/user/project/img/koding_start-build.pngbin27926 -> 27925 bytes
-rw-r--r--doc/user/project/img/labels_generate_default.pngbin65549 -> 25797 bytes
-rw-r--r--doc/user/project/img/labels_group_issues.pngbin264573 -> 92070 bytes
-rw-r--r--doc/user/project/img/labels_list.pngbin207736 -> 71323 bytes
-rw-r--r--doc/user/project/img/labels_prioritized.pngbin156020 -> 56353 bytes
-rw-r--r--doc/user/project/img/labels_project_list_search.pngbin175669 -> 100066 bytes
-rw-r--r--doc/user/project/img/labels_promotion.pngbin121824 -> 44021 bytes
-rw-r--r--doc/user/project/img/labels_sidebar.pngbin31123 -> 12109 bytes
-rw-r--r--doc/user/project/img/labels_sidebar_assign.pngbin28033 -> 11024 bytes
-rw-r--r--doc/user/project/img/labels_sidebar_inline.pngbin28423 -> 11083 bytes
-rw-r--r--doc/user/project/img/labels_sort_label_priority.pngbin110154 -> 42263 bytes
-rw-r--r--doc/user/project/img/labels_sort_priority.pngbin108780 -> 41486 bytes
-rw-r--r--doc/user/project/img/labels_subscriptions.pngbin87502 -> 31716 bytes
-rw-r--r--doc/user/project/img/priority_sort_order.pngbin102242 -> 69978 bytes
-rw-r--r--doc/user/project/img/project_overview_badges.pngbin40188 -> 12486 bytes
-rw-r--r--doc/user/project/img/project_repository_settings.pngbin17872 -> 7511 bytes
-rw-r--r--doc/user/project/img/protected_branches_delete.pngbin21510 -> 21507 bytes
-rw-r--r--doc/user/project/img/protected_branches_devs_can_push.pngbin34888 -> 11221 bytes
-rw-r--r--doc/user/project/img/protected_branches_error_ui.pngbin13125 -> 13117 bytes
-rw-r--r--doc/user/project/img/protected_branches_list.pngbin6937 -> 6933 bytes
-rw-r--r--doc/user/project/img/protected_branches_page.pngbin7205 -> 7199 bytes
-rw-r--r--doc/user/project/img/protected_tag_matches.pngbin85305 -> 23054 bytes
-rw-r--r--doc/user/project/img/protected_tags_list.pngbin24490 -> 7227 bytes
-rw-r--r--doc/user/project/img/protected_tags_page.pngbin56112 -> 13813 bytes
-rw-r--r--doc/user/project/img/protected_tags_permissions_dropdown.pngbin26514 -> 7770 bytes
-rw-r--r--doc/user/project/import/img/bitbucket_server_import_credentials.pngbin40566 -> 13781 bytes
-rw-r--r--doc/user/project/import/img/bitbucket_server_import_select_project.pngbin56750 -> 19427 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_login.pngbin13751 -> 13452 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_select_fogbogz.pngbin12289 -> 12283 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_select_project.pngbin20905 -> 20335 bytes
-rw-r--r--doc/user/project/import/img/import_projects_from_gitea_new_import.pngbin15561 -> 15518 bytes
-rw-r--r--doc/user/project/import/img/import_projects_from_github_select_auth_method.pngbin17612 -> 17611 bytes
-rw-r--r--doc/user/project/import/img/import_projects_from_new_project_page.pngbin81639 -> 30489 bytes
-rw-r--r--doc/user/project/integrations/img/hangouts_chat_configuration.pngbin101788 -> 44655 bytes
-rw-r--r--doc/user/project/integrations/img/issue_configuration.pngbin20288 -> 11882 bytes
-rw-r--r--doc/user/project/integrations/img/jira_group_access.pngbin19235 -> 19147 bytes
-rw-r--r--doc/user/project/integrations/img/jira_project_name.pngbin26685 -> 26680 bytes
-rw-r--r--doc/user/project/integrations/img/jira_project_settings.pngbin32791 -> 14149 bytes
-rw-r--r--doc/user/project/integrations/img/jira_service.pngbin37869 -> 36976 bytes
-rw-r--r--doc/user/project/integrations/img/jira_service_close_comment.pngbin11893 -> 11890 bytes
-rw-r--r--doc/user/project/integrations/img/jira_service_page.pngbin193364 -> 47533 bytes
-rw-r--r--doc/user/project/integrations/img/jira_user_management_link.pngbin23921 -> 23906 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_bot_auth.pngbin8676 -> 8669 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_bot_available_commands.pngbin4647 -> 4642 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_configuration.pngbin249592 -> 101151 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_console_integrations.pngbin314642 -> 114618 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_gitlab_token.pngbin3688 -> 3673 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_goto_console.pngbin7754 -> 7746 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_slash_command_configuration.pngbin24169 -> 24162 bytes
-rw-r--r--doc/user/project/integrations/img/mattermost_team_integrations.pngbin4766 -> 4757 bytes
-rw-r--r--doc/user/project/integrations/img/merge_request_performance.pngbin60194 -> 40917 bytes
-rw-r--r--doc/user/project/integrations/img/microsoft_teams_configuration.pngbin350592 -> 96509 bytes
-rw-r--r--doc/user/project/integrations/img/project_services.pngbin25753 -> 11109 bytes
-rw-r--r--doc/user/project/integrations/img/prometheus_dashboard.pngbin26112 -> 12650 bytes
-rw-r--r--doc/user/project/integrations/img/prometheus_deploy.pngbin27258 -> 8413 bytes
-rw-r--r--doc/user/project/integrations/img/prometheus_yaml_deploy.pngbin23567 -> 9456 bytes
-rw-r--r--doc/user/project/integrations/img/redmine_configuration.pngbin10266 -> 10254 bytes
-rw-r--r--doc/user/project/integrations/img/services_templates_redmine_example.pngbin8608 -> 8336 bytes
-rw-r--r--doc/user/project/integrations/img/slack_configuration.pngbin229050 -> 92179 bytes
-rw-r--r--doc/user/project/integrations/img/webhook_logs.pngbin132319 -> 38687 bytes
-rw-r--r--doc/user/project/integrations/img/webhook_testing.pngbin191267 -> 55578 bytes
-rw-r--r--doc/user/project/integrations/img/webhooks_ssl.pngbin27799 -> 27790 bytes
-rw-r--r--doc/user/project/issues/img/confidential_issues_index_page.pngbin107117 -> 30634 bytes
-rw-r--r--doc/user/project/issues/img/delete_issue.pngbin49894 -> 13973 bytes
-rw-r--r--doc/user/project/issues/img/due_dates_create.pngbin6992 -> 6895 bytes
-rw-r--r--doc/user/project/issues/img/group_issues_list_view.pngbin127781 -> 46595 bytes
-rw-r--r--doc/user/project/issues/img/issue_board.pngbin56253 -> 55931 bytes
-rw-r--r--doc/user/project/issues/img/issue_template.pngbin25022 -> 25019 bytes
-rw-r--r--doc/user/project/issues/img/new_issue_from_email.pngbin13461 -> 4259 bytes
-rw-r--r--doc/user/project/issues/img/new_issue_from_issue_board.pngbin57427 -> 20063 bytes
-rw-r--r--doc/user/project/issues/img/new_issue_from_projects_dashboard.pngbin23685 -> 9674 bytes
-rw-r--r--doc/user/project/issues/img/project_issues_list_view.pngbin196071 -> 77189 bytes
-rw-r--r--doc/user/project/issues/img/sidebar_confidential_issue.pngbin10210 -> 4648 bytes
-rw-r--r--doc/user/project/issues/img/sidebar_move_issue.pngbin50132 -> 50003 bytes
-rw-r--r--doc/user/project/issues/img/sidebar_not_confidential_issue.pngbin8163 -> 4081 bytes
-rw-r--r--doc/user/project/issues/img/turn_off_confidentiality.pngbin27307 -> 10851 bytes
-rw-r--r--doc/user/project/issues/img/turn_on_confidentiality.pngbin33499 -> 13513 bytes
-rw-r--r--doc/user/project/members/img/access_requests_management.pngbin11018 -> 11005 bytes
-rw-r--r--doc/user/project/members/img/add_new_user_to_project_settings.pngbin11046 -> 11004 bytes
-rw-r--r--doc/user/project/members/img/add_user_email_accept.pngbin16890 -> 16878 bytes
-rw-r--r--doc/user/project/members/img/add_user_import_members_from_another_project.pngbin25343 -> 25333 bytes
-rw-r--r--doc/user/project/members/img/add_user_members_menu.pngbin28994 -> 28988 bytes
-rw-r--r--doc/user/project/members/img/max_access_level.pngbin34718 -> 34710 bytes
-rw-r--r--doc/user/project/members/img/request_access_button.pngbin25281 -> 25271 bytes
-rw-r--r--doc/user/project/members/img/withdraw_access_request_button.pngbin26135 -> 26123 bytes
-rw-r--r--doc/user/project/merge_requests/img/allow_collaboration.pngbin39513 -> 21522 bytes
-rw-r--r--doc/user/project/merge_requests/img/cherry_pick_changes_commit.pngbin13604 -> 13568 bytes
-rw-r--r--doc/user/project/merge_requests/img/cherry_pick_changes_mr.pngbin16494 -> 7214 bytes
-rw-r--r--doc/user/project/merge_requests/img/create_from_email.pngbin152975 -> 55777 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_conflict_editor.pngbin50422 -> 50286 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_request.pngbin748131 -> 386345 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_request_diff_file_navigation.pngbin244736 -> 112288 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_request_widget.pngbin11039 -> 11036 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.pngbin22791 -> 10186 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_msg.pngbin5251 -> 5237 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.pngbin25783 -> 6491 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_status.pngbin69953 -> 21397 bytes
-rw-r--r--doc/user/project/merge_requests/img/project_merge_requests_list_view.pngbin325819 -> 171866 bytes
-rw-r--r--doc/user/project/merge_requests/img/remove_source_branch_status.pngbin32649 -> 32586 bytes
-rw-r--r--doc/user/project/merge_requests/img/revert_changes_commit.pngbin95655 -> 95647 bytes
-rw-r--r--doc/user/project/merge_requests/img/revert_changes_mr.pngbin104972 -> 104954 bytes
-rw-r--r--doc/user/project/merge_requests/img/squash_edit_form.pngbin4232 -> 4231 bytes
-rw-r--r--doc/user/project/merge_requests/img/squash_mr_commits.pngbin85635 -> 31491 bytes
-rw-r--r--doc/user/project/merge_requests/img/squash_mr_widget.pngbin6496 -> 3573 bytes
-rw-r--r--doc/user/project/merge_requests/img/squash_squashed_commit.pngbin63371 -> 23726 bytes
-rw-r--r--doc/user/project/merge_requests/img/versions.pngbin23629 -> 22763 bytes
-rw-r--r--doc/user/project/merge_requests/img/versions_compare.pngbin17228 -> 17017 bytes
-rw-r--r--doc/user/project/merge_requests/img/versions_dropdown.pngbin13887 -> 13827 bytes
-rw-r--r--doc/user/project/merge_requests/img/versions_system_note.pngbin7136 -> 7126 bytes
-rw-r--r--doc/user/project/merge_requests/img/wip_blocked_accept_button.pngbin8071 -> 4152 bytes
-rw-r--r--doc/user/project/merge_requests/img/wip_mark_as_wip.pngbin17081 -> 7961 bytes
-rw-r--r--doc/user/project/merge_requests/img/wip_unmark_as_wip.pngbin18585 -> 8424 bytes
-rw-r--r--doc/user/project/milestones/img/milestones_new_group_milestone.pngbin276831 -> 144554 bytes
-rw-r--r--doc/user/project/milestones/img/milestones_new_project_milestone.pngbin257285 -> 133541 bytes
-rw-r--r--doc/user/project/milestones/img/milestones_project_milestone_page.pngbin489382 -> 270005 bytes
-rw-r--r--doc/user/project/milestones/img/milestones_promote_milestone.pngbin76864 -> 49288 bytes
-rw-r--r--doc/user/project/pages/img/dns_add_new_a_record_example_updated_2018.pngbin7704 -> 3701 bytes
-rw-r--r--doc/user/project/pages/img/pages_create_project.pngbin6063 -> 6062 bytes
-rw-r--r--doc/user/project/pages/img/pages_dns_details.pngbin5351 -> 5350 bytes
-rw-r--r--doc/user/project/pages/img/pages_multiple_domains.pngbin12936 -> 12930 bytes
-rw-r--r--doc/user/project/pages/img/pages_remove.pngbin3810 -> 3777 bytes
-rw-r--r--doc/user/project/pages/img/pages_upload_cert.pngbin22907 -> 22888 bytes
-rw-r--r--doc/user/project/pages/img/verify_your_domain.pngbin30163 -> 12082 bytes
-rw-r--r--doc/user/project/pipelines/img/job_artifacts_pipelines_page.pngbin16550 -> 16403 bytes
-rw-r--r--doc/user/project/pipelines/img/pipeline_schedule_play.pngbin39142 -> 11400 bytes
-rw-r--r--doc/user/project/pipelines/img/pipeline_schedule_variables.pngbin13478 -> 5360 bytes
-rw-r--r--doc/user/project/pipelines/img/pipeline_schedules_list.pngbin38034 -> 12948 bytes
-rw-r--r--doc/user/project/pipelines/img/pipeline_schedules_new_form.pngbin72501 -> 23290 bytes
-rw-r--r--doc/user/project/pipelines/img/pipeline_schedules_ownership.pngbin12043 -> 5004 bytes
-rw-r--r--doc/user/project/repository/branches/img/delete_merged_branches.pngbin42891 -> 42886 bytes
-rw-r--r--doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.pngbin24514 -> 13008 bytes
-rw-r--r--doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.pngbin4403 -> 4366 bytes
-rw-r--r--doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.pngbin113801 -> 42290 bytes
-rw-r--r--doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.pngbin12924 -> 7188 bytes
-rw-r--r--doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.pngbin20652 -> 9771 bytes
-rw-r--r--doc/user/project/repository/img/compare_branches.pngbin206831 -> 131046 bytes
-rw-r--r--doc/user/project/repository/img/repository_languages.pngbin88244 -> 26516 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_branch_dropdown.pngbin10386 -> 10324 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_branch_from_issue.pngbin2720 -> 2715 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_branch_page.pngbin6034 -> 5886 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_directory_dialog.pngbin7323 -> 7157 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_directory_dropdown.pngbin9918 -> 9916 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_file_dropdown.pngbin10233 -> 10152 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_push_widget.pngbin3395 -> 3388 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_new_tag_dropdown.pngbin9796 -> 9706 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_start_new_merge_request.pngbin4060 -> 4049 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_template_dropdown_buttons.pngbin5634 -> 5629 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_template_dropdown_first_file.pngbin8846 -> 8844 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_upload_file_dialog.pngbin12558 -> 12553 bytes
-rw-r--r--doc/user/project/repository/img/web_editor_upload_file_dropdown.pngbin10291 -> 10200 bytes
-rw-r--r--doc/user/project/settings/img/import_export_download_export.pngbin24482 -> 24397 bytes
-rw-r--r--doc/user/project/settings/img/import_export_export_button.pngbin24122 -> 24118 bytes
-rw-r--r--doc/user/project/settings/img/import_export_new_project.pngbin13083 -> 13082 bytes
-rw-r--r--doc/user/project/settings/img/import_export_select_file.pngbin13713 -> 13514 bytes
-rw-r--r--doc/user/project/settings/img/settings_edit_button.pngbin6901 -> 6897 bytes
-rw-r--r--doc/user/project/settings/img/sharing_and_permissions_settings.pngbin143341 -> 50602 bytes
-rw-r--r--doc/user/project/web_ide/img/open_web_ide.pngbin28574 -> 28571 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_create_home_page.pngbin12422 -> 12421 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_create_new_page.pngbin38105 -> 14957 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_create_new_page_modal.pngbin13189 -> 5831 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_move_page_1.pngbin54550 -> 17270 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_move_page_2.pngbin33535 -> 10571 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_page_history.pngbin26478 -> 12101 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_sidebar.pngbin7440 -> 3178 bytes
-rw-r--r--doc/user/search/img/issue_search_by_term.pngbin127492 -> 35648 bytes
-rw-r--r--doc/user/search/img/issue_search_filter.pngbin69559 -> 27091 bytes
-rw-r--r--doc/user/search/img/issues_mrs_shortcut.pngbin61888 -> 26706 bytes
-rw-r--r--doc/user/search/img/project_search.pngbin89002 -> 42139 bytes
-rw-r--r--doc/workflow/ci_mr.pngbin12034 -> 12024 bytes
-rw-r--r--doc/workflow/environment_branches.pngbin12364 -> 12354 bytes
-rw-r--r--doc/workflow/forking/branch_select.pngbin15424 -> 15410 bytes
-rw-r--r--doc/workflow/forking/merge_request.pngbin16332 -> 16329 bytes
-rw-r--r--doc/workflow/git_pull.pngbin28749 -> 28701 bytes
-rw-r--r--doc/workflow/gitlab_flow.pngbin47432 -> 47430 bytes
-rw-r--r--doc/workflow/good_commit.pngbin8742 -> 8740 bytes
-rw-r--r--doc/workflow/img/file_finder_find_button.pngbin14567 -> 14565 bytes
-rw-r--r--doc/workflow/img/forking_workflow_fork_button.pngbin12973 -> 12962 bytes
-rw-r--r--doc/workflow/img/forking_workflow_path_taken_error.pngbin10103 -> 10092 bytes
-rw-r--r--doc/workflow/img/notification_group_settings.pngbin171784 -> 54362 bytes
-rw-r--r--doc/workflow/img/notification_project_settings.pngbin167548 -> 58864 bytes
-rw-r--r--doc/workflow/img/todo_list_item.pngbin18777 -> 18776 bytes
-rw-r--r--doc/workflow/img/todos_add_todo_sidebar.pngbin42360 -> 17524 bytes
-rw-r--r--doc/workflow/img/todos_mark_done_sidebar.pngbin42317 -> 17619 bytes
-rw-r--r--doc/workflow/merge_request.pngbin47240 -> 47225 bytes
-rw-r--r--doc/workflow/messy_flow.pngbin11665 -> 11663 bytes
-rw-r--r--doc/workflow/mr_inline_comments.pngbin52519 -> 52503 bytes
-rw-r--r--doc/workflow/production_branch.pngbin7264 -> 7262 bytes
-rw-r--r--doc/workflow/rebase.pngbin29009 -> 28939 bytes
-rw-r--r--doc/workflow/release_branches.pngbin12746 -> 12736 bytes
-rw-r--r--doc/workflow/releases/new_tag.pngbin42456 -> 42439 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_detect_host_keys.pngbin61463 -> 22952 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_diverged_branch_push.pngbin9512 -> 9509 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_hard_failed_main.pngbin47943 -> 15555 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_hard_failed_settings.pngbin53279 -> 16414 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_pull_advanced_host_keys.pngbin115796 -> 40414 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_pull_settings.pngbin100470 -> 39909 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_pull_settings_for_ssh.pngbin69467 -> 26234 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_ssh_host_keys_verified.pngbin23724 -> 9343 bytes
-rw-r--r--doc/workflow/repository_mirroring/repository_mirroring_ssh_public_key_authentication.pngbin82456 -> 27440 bytes
-rw-r--r--doc/workflow/time-tracking/time-tracking-example.pngbin48350 -> 14564 bytes
-rw-r--r--doc/workflow/time-tracking/time-tracking-sidebar.pngbin19467 -> 9068 bytes
-rw-r--r--lib/api/api.rb9
-rw-r--r--lib/api/award_emoji.rb2
-rw-r--r--lib/api/entities.rb5
-rw-r--r--lib/api/group_milestones.rb14
-rw-r--r--lib/api/helpers/notes_helpers.rb5
-rw-r--r--lib/api/issues.rb11
-rw-r--r--lib/api/project_milestones.rb3
-rw-r--r--lib/api/protected_tags.rb79
-rw-r--r--lib/banzai/reference_parser/merge_request_parser.rb5
-rw-r--r--lib/feature.rb3
-rw-r--r--lib/gitlab/auth/ldap/access.rb24
-rw-r--r--lib/gitlab/auth/o_auth/provider.rb1
-rw-r--r--lib/gitlab/bitbucket_server_import/importer.rb18
-rw-r--r--lib/gitlab/ci/status/build/failed.rb2
-rw-r--r--lib/gitlab/diff/highlight.rb2
-rw-r--r--lib/gitlab/diff/line.rb9
-rw-r--r--lib/gitlab/github_import.rb18
-rw-r--r--lib/gitlab/github_import/importer/issue_importer.rb4
-rw-r--r--lib/gitlab/github_import/importer/pull_request_importer.rb92
-rw-r--r--lib/gitlab/i18n.rb1
-rw-r--r--lib/gitlab/import/database_helpers.rb25
-rw-r--r--lib/gitlab/import/merge_request_creator.rb40
-rw-r--r--lib/gitlab/import/merge_request_helpers.rb70
-rw-r--r--lib/gitlab/import_export/uploads_manager.rb19
-rw-r--r--lib/gitlab/middleware/multipart.rb10
-rw-r--r--lib/gitlab/url_blocker.rb8
-rw-r--r--lib/gitlab/usage_data.rb3
-rw-r--r--lib/tasks/gettext.rake13
-rw-r--r--locale/gitlab.pot43
-rw-r--r--qa/qa.rb1
-rw-r--r--qa/qa/page/project/import/github.rb2
-rw-r--r--qa/qa/scenario/template.rb8
-rw-r--r--qa/qa/scenario/test/instance.rb41
-rw-r--r--qa/qa/specs/features/api/1_manage/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/1_manage/users_spec.rb (renamed from qa/qa/specs/features/api/users_spec.rb)26
-rw-r--r--qa/qa/specs/features/api/2_plan/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/3_create/repository/files_spec.rb (renamed from qa/qa/specs/features/api/basics_spec.rb)0
-rw-r--r--qa/qa/specs/features/api/4_verify/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/5_package/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/6_release/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/7_configure/.gitkeep0
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb17
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb23
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb21
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb26
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb110
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb24
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb22
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb57
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb25
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb45
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb54
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb (renamed from qa/qa/specs/features/repository/clone_spec.rb)6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb58
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb (renamed from qa/qa/specs/features/repository/push_spec.rb)6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb70
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb49
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb87
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb32
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/secret_variable/add_secret_variable_spec.rb28
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/.gitkeep0
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb23
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb109
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb68
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb21
-rw-r--r--qa/qa/specs/features/login/basic_spec.rb15
-rw-r--r--qa/qa/specs/features/login/ldap_spec.rb19
-rw-r--r--qa/qa/specs/features/mattermost/group_create_spec.rb17
-rw-r--r--qa/qa/specs/features/mattermost/login_spec.rb17
-rw-r--r--qa/qa/specs/features/merge_request/create_spec.rb53
-rw-r--r--qa/qa/specs/features/merge_request/rebase_spec.rb39
-rw-r--r--qa/qa/specs/features/merge_request/squash_spec.rb50
-rw-r--r--qa/qa/specs/features/project/activity_spec.rb20
-rw-r--r--qa/qa/specs/features/project/add_deploy_key_spec.rb19
-rw-r--r--qa/qa/specs/features/project/add_secret_variable_spec.rb24
-rw-r--r--qa/qa/specs/features/project/auto_devops_spec.rb64
-rw-r--r--qa/qa/specs/features/project/create_issue_spec.rb18
-rw-r--r--qa/qa/specs/features/project/create_spec.rb22
-rw-r--r--qa/qa/specs/features/project/deploy_key_clone_spec.rb105
-rw-r--r--qa/qa/specs/features/project/file_spec.rb54
-rw-r--r--qa/qa/specs/features/project/fork_project_spec.rb21
-rw-r--r--qa/qa/specs/features/project/import_from_github_spec.rb106
-rw-r--r--qa/qa/specs/features/project/pipelines_spec.rb102
-rw-r--r--qa/qa/specs/features/project/wikis_spec.rb45
-rw-r--r--qa/qa/specs/features/repository/protected_branches_spec.rb66
-rw-r--r--qa/spec/runtime/env_spec.rb4
-rw-r--r--qa/spec/scenario/test/instance/all_spec.rb8
-rw-r--r--qa/spec/scenario/test/instance/smoke_spec.rb2
-rw-r--r--rubocop/cop/line_break_around_conditional_block.rb6
-rw-r--r--rubocop/cop/ruby_interpolation_in_translation.rb29
-rw-r--r--rubocop/rubocop.rb1
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb11
-rw-r--r--spec/controllers/projects/merge_requests/creations_controller_spec.rb49
-rw-r--r--spec/factories/milestones.rb2
-rw-r--r--spec/features/admin/admin_users_spec.rb1
-rw-r--r--spec/features/dashboard/milestones_spec.rb3
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb54
-rw-r--r--spec/features/milestones/user_deletes_milestone_spec.rb44
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb10
-rw-r--r--spec/features/projects/jobs/user_browses_job_spec.rb4
-rw-r--r--spec/features/projects/jobs/user_browses_jobs_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb4
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb2
-rw-r--r--spec/helpers/import_helper_spec.rb10
-rw-r--r--spec/javascripts/badges/dummy_badge.js3
-rw-r--r--spec/javascripts/flash_spec.js7
-rw-r--r--spec/javascripts/helpers/vue_mount_component_helper.js10
-rw-r--r--spec/javascripts/ide/stores/modules/commit/actions_spec.js28
-rw-r--r--spec/javascripts/jobs/components/environments_block_spec.js137
-rw-r--r--spec/javascripts/performance_bar/services/performance_bar_service_spec.js63
-rw-r--r--spec/javascripts/pipelines/graph/dropdown_job_component_spec.js8
-rw-r--r--spec/javascripts/pipelines/graph/job_component_spec.js20
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js14
-rw-r--r--spec/javascripts/vue_shared/components/stacked_progress_bar_spec.js6
-rw-r--r--spec/javascripts/vue_shared/components/tooltip_on_truncate_spec.js162
-rw-r--r--spec/lib/feature_spec.rb66
-rw-r--r--spec/lib/gitlab/auth/ldap/access_spec.rb152
-rw-r--r--spec/lib/gitlab/auth/o_auth/provider_spec.rb42
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/failed_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/retried_spec.rb2
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb4
-rw-r--r--spec/lib/gitlab/diff/highlight_spec.rb10
-rw-r--r--spec/lib/gitlab/diff/line_spec.rb22
-rw-r--r--spec/lib/gitlab/github_import/importer/issue_importer_spec.rb8
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import_spec.rb33
-rw-r--r--spec/lib/gitlab/import/database_helpers_spec.rb46
-rw-r--r--spec/lib/gitlab/import/merge_request_creator_spec.rb43
-rw-r--r--spec/lib/gitlab/import_export/uploads_manager_spec.rb32
-rw-r--r--spec/lib/gitlab/middleware/multipart_spec.rb20
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb25
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb3
-rw-r--r--spec/migrations/drop_duplicate_protected_tags_spec.rb40
-rw-r--r--spec/models/concerns/awardable_spec.rb11
-rw-r--r--spec/models/issue_spec.rb99
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/remote_mirror_spec.rb12
-rw-r--r--spec/models/repository_spec.rb18
-rw-r--r--spec/policies/group_policy_spec.rb3
-rw-r--r--spec/policies/project_policy_spec.rb1
-rw-r--r--spec/presenters/ci/build_presenter_spec.rb12
-rw-r--r--spec/requests/api/award_emoji_spec.rb12
-rw-r--r--spec/requests/api/issues_spec.rb61
-rw-r--r--spec/requests/api/labels_spec.rb8
-rw-r--r--spec/requests/api/project_milestones_spec.rb13
-rw-r--r--spec/requests/api/protected_tags_spec.rb202
-rw-r--r--spec/routing/admin_routing_spec.rb4
-rw-r--r--spec/routing/project_routing_spec.rb6
-rw-r--r--spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb68
-rw-r--r--spec/serializers/build_serializer_spec.rb2
-rw-r--r--spec/serializers/job_entity_spec.rb4
-rw-r--r--spec/services/git_push_service_spec.rb40
-rw-r--r--spec/services/groups/destroy_service_spec.rb8
-rw-r--r--spec/services/issues/fetch_referenced_merge_requests_service_spec.rb35
-rw-r--r--spec/services/issues/referenced_merge_requests_service_spec.rb133
-rw-r--r--spec/services/merge_requests/build_service_spec.rb4
-rw-r--r--spec/services/milestones/destroy_service_spec.rb28
-rw-r--r--spec/services/projects/update_remote_mirror_service_spec.rb1
-rw-r--r--spec/services/projects/update_service_spec.rb29
-rw-r--r--spec/support/api/milestones_shared_examples.rb18
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb4
-rw-r--r--spec/support/helpers/ldap_helpers.rb17
-rw-r--r--spec/support/helpers/stub_configuration.rb4
-rw-r--r--spec/support/helpers/stub_feature_flags.rb3
-rw-r--r--spec/support/shared_examples/requests/api/notes.rb82
-rw-r--r--spec/views/projects/merge_requests/_commits.html.haml_spec.rb13
-rw-r--r--spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb15
826 files changed, 4602 insertions, 1984 deletions
diff --git a/.flayignore b/.flayignore
index 4b6f7ba693a..87411516a2a 100644
--- a/.flayignore
+++ b/.flayignore
@@ -6,6 +6,7 @@ app/controllers/projects/approvers_controller.rb
app/controllers/projects/protected_branches/merge_access_levels_controller.rb
app/controllers/projects/protected_branches/push_access_levels_controller.rb
app/controllers/projects/protected_tags/create_access_levels_controller.rb
+app/helpers/system_note_helper.rb
app/policies/project_policy.rb
app/models/concerns/relative_positioning.rb
app/workers/stuck_merge_jobs_worker.rb
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 797a20ef16e..23d71675ae4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -131,7 +131,7 @@ stages:
.single-script-job: &single-script-job
image: ruby:2.4-alpine
before_script: []
- stage: build
+ stage: test
cache: {}
dependencies: []
variables: &single-script-job-variables
diff --git a/.gitlab/issue_templates/Test plan.md b/.gitlab/issue_templates/Test plan.md
new file mode 100644
index 00000000000..580fab206b3
--- /dev/null
+++ b/.gitlab/issue_templates/Test plan.md
@@ -0,0 +1,96 @@
+# Test Plan
+
+<!-- This issue outlines testing activities related to a particular issue or epic.
+
+[Here is an example test plan](https://gitlab.com/gitlab-org/gitlab-ce/issues/50353)
+
+This and other comments should be removed as you write the plan -->
+
+## Introduction
+
+<!-- Briefly outline what is being tested
+
+Mention the issue(s) this test plan is related to -->
+
+## Scope
+
+<!-- State any limits on aspects of the feature being tested
+Outline the types of data to be included
+Outline the types of tests to be performed (functional, security, performance,
+database, automated, etc) -->
+
+## ACC Matrix
+
+<!-- Use the matrix below as a template to identify the Attributes, Components, and
+Capabilities relevant to the scope of this test plan. Add or remove Attributes
+and Components as required and list Capabilities in the next section
+
+Attributes (columns) are adverbs or adjectives that describe (at a high level)
+the qualities testing is meant to ensure Components have.
+
+Components (rows) are nouns that define major parts of the product being tested.
+
+Capabilities link Attributes and Components. They are what your product needs to
+do to make sure a Component fulfills an Attribute
+
+For more information see the [Google Testing Blog article about the 10 minute
+test plan](https://testing.googleblog.com/2011/09/10-minute-test-plan.html) and
+[this wiki page from an open-source tool that implements the ACC
+model](https://code.google.com/archive/p/test-analytics/wikis/AccExplained.wiki). -->
+
+| | Simple | Secure | Responsive | Obvious | Stable |
+|------------|:------:|:------:|:----------:|:-------:|:------:|
+| Admin | | | | | |
+| Groups | | | | | |
+| Project | | | | | |
+| Repository | | | | | |
+| Issues | | | | | |
+| MRs | | | | | |
+| CI/CD | | | | | |
+| Ops | | | | | |
+| Registry | | | | | |
+| Wiki | | | | | |
+| Snippets | | | | | |
+| Settings | | | | | |
+| Tracking | | | | | |
+| API | | | | | |
+
+## Capabilities
+
+<!-- Use the ACC matrix above to help you identify Capabilities at each relevant
+intersection of Components and Attributes.
+
+Some features might be simple enough that they only involve one Component, while
+more complex features could involve multiple or even all.
+
+Example (from https://gitlab.com/gitlab-org/gitlab-ce/issues/50353):
+* Respository is
+ * Simple
+ * It's easy to select the desired file template
+ * It doesn't require unnecessary actions to save the change
+ * It's easy to undo the change after selecting a template
+ * Responsive
+ * The list of templates can be restricted to allow a user to find a specific template among many
+ * Once a template is selected the file content updates quickly and smoothly
+-->
+
+## Test Plan
+
+<!-- If the scope is small enough you may not need to write a list of tests to
+perform. It might be enough to use the Capabilities to guide your testing.
+
+If the feature is more complex, especially if it involves multiple Components,
+briefly outline a set of tests here. When identifying tests to perform be sure
+to consider risk. Note inherent/known levels of risk so that testing can focus
+on high risk areas first.
+
+New end-to-end and integration tests (Selenium and API) should be added to the
+[Test Coverage sheet](https://docs.google.com/spreadsheets/d/1RlLfXGboJmNVIPP9jgFV5sXIACGfdcFq1tKd7xnlb74/)
+
+Please note if automated tests already exist.
+
+When adding new automated tests, please keep [testing levels](https://docs.gitlab.com/ce/development/testing_guide/testing_levels.html)
+in mind.
+-->
+
+/label ~Quality \ No newline at end of file
diff --git a/.haml-lint.yml b/.haml-lint.yml
index 32c7de0fb78..fcdc47af60f 100644
--- a/.haml-lint.yml
+++ b/.haml-lint.yml
@@ -70,14 +70,15 @@ linters:
enabled: false
RuboCop:
- enabled: false
+ enabled: true
# These cops are incredibly noisy when it comes to HAML templates, so we
# ignore them.
ignored_cops:
- - Lint/BlockAlignment
- - Lint/EndAlignment
+ - Layout/BlockAlignment
+ - Layout/EndAlignment
- Lint/Void
- Metrics/LineLength
+ - Naming/FileName
- Style/AlignParameters
- Style/BlockNesting
- Style/ElseAlignment
@@ -91,6 +92,52 @@ linters:
- Style/TrailingWhitespace
- Style/WhileUntilModifier
+ # These cops should eventually get enabled
+ - Cop/LineBreakAfterGuardClauses
+ - Cop/LineBreakAroundConditionalBlock
+ - Cop/ProjectPathHelper
+ - GitlabSecurity/PublicSend
+ - Layout/LeadingCommentSpace
+ - Layout/SpaceAfterColon
+ - Layout/SpaceAfterComma
+ - Layout/SpaceAroundOperators
+ - Layout/SpaceBeforeBlockBraces
+ - Layout/SpaceBeforeComma
+ - Layout/SpaceBeforeFirstArg
+ - Layout/SpaceInsideArrayLiteralBrackets
+ - Layout/SpaceInsideHashLiteralBraces
+ - Layout/SpaceInsideStringInterpolation
+ - Layout/TrailingBlankLines
+ - Lint/BooleanSymbol
+ - Lint/LiteralInInterpolation
+ - Lint/ParenthesesAsGroupedExpression
+ - Lint/RedundantWithIndex
+ - Lint/Syntax
+ - Lint/UselessAssignment
+ - Metrics/BlockNesting
+ - Naming/VariableName
+ - Performance/RedundantMatch
+ - Performance/StringReplacement
+ - Rails/Presence
+ - Rails/RequestReferer
+ - Style/AndOr
+ - Style/ColonMethodCall
+ - Style/ConditionalAssignment
+ - Style/HashSyntax
+ - Style/IdenticalConditionalBranches
+ - Style/NegatedIf
+ - Style/NestedTernaryOperator
+ - Style/Not
+ - Style/ParenthesesAroundCondition
+ - Style/RedundantParentheses
+ - Style/SelfAssignment
+ - Style/Semicolon
+ - Style/TernaryParentheses
+ - Style/TrailingCommaInHashLiteral
+ - Style/UnlessElse
+ - Style/WordArray
+ - Style/ZeroLengthPredicate
+
RubyComments:
enabled: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aee36bb6df3..5e022b7e52b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,31 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 11.2.3 (2018-08-28)
+
+- No changes.
+
+## 11.2.2 (2018-08-27)
+
+### Security (3 changes)
+
+- Fixed persistent XSS rendering/escaping of diff location lines.
+- Adding CSRF protection to Hooks resend action.
+- Block link-local addresses in URLBlocker.
+
+
+## 11.2.1 (2018-08-22)
+
+### Fixed (2 changes)
+
+- Fix wrong commit count in push event payload. !21338
+- Fix broken Git over HTTP clones with LDAP users. !21352
+
+### Performance (1 change)
+
+- Eliminate unnecessary and duplicate system hook fires. !21337
+
+
## 11.2.0 (2018-08-22)
### Security (5 changes)
@@ -242,6 +267,23 @@ entry.
- Moves help_popover component to a common location.
+## 11.1.6 (2018-08-28)
+
+- No changes.
+
+## 11.1.5 (2018-08-27)
+
+### Security (3 changes)
+
+- Fixed persistent XSS rendering/escaping of diff location lines.
+- Adding CSRF protection to Hooks resend action.
+- Block link-local addresses in URLBlocker.
+
+### Fixed (1 change, 1 of them is from the community)
+
+- Sanitize git URL in import errors. (Jamie Schembri)
+
+
## 11.1.4 (2018-07-30)
### Fixed (4 changes, 1 of them is from the community)
@@ -524,6 +566,19 @@ entry.
- Use monospaced font for MR diff commit link ref on GFM.
+## 11.0.6 (2018-08-27)
+
+### Security (3 changes)
+
+- Fixed persistent XSS rendering/escaping of diff location lines.
+- Adding CSRF protection to Hooks resend action.
+- Block link-local addresses in URLBlocker.
+
+### Fixed (1 change, 1 of them is from the community)
+
+- Sanitize git URL in import errors. (Jamie Schembri)
+
+
## 11.0.5 (2018-07-26)
### Security (4 changes)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fb7c0c88629..1b9e9d4a5a3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -314,7 +314,7 @@ This [documentation](doc/development/contributing/merge_request_workflow.md) has
## Definition of done
-This [documentation](doc/development/contributing/merge_request_workflow.md)) has been moved.
+This [documentation](doc/development/contributing/merge_request_workflow.md) has been moved.
## Style guides
diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock
index f9ec29cde90..63b450d3f62 100644
--- a/Gemfile.rails5.lock
+++ b/Gemfile.rails5.lock
@@ -126,7 +126,7 @@ GEM
numerizer (~> 0.1.1)
chunky_png (1.3.5)
citrus (3.0.2)
- coderay (1.1.1)
+ coderay (1.1.2)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
commonmarker (0.17.8)
@@ -495,7 +495,7 @@ GEM
memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
- method_source (0.8.2)
+ method_source (0.9.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
@@ -638,12 +638,11 @@ GEM
unparser
procto (0.0.3)
prometheus-client-mmap (0.9.4)
- pry (0.10.4)
+ pry (0.11.3)
coderay (~> 1.1.0)
- method_source (~> 0.8.1)
- slop (~> 3.4)
- pry-byebug (3.4.2)
- byebug (~> 9.0)
+ method_source (~> 0.9.0)
+ pry-byebug (3.4.3)
+ byebug (>= 9.0, < 9.1)
pry (~> 0.10)
pry-rails (0.3.5)
pry (>= 0.9.10)
@@ -751,7 +750,7 @@ GEM
retriable (3.1.2)
rinku (2.0.0)
rotp (2.1.2)
- rouge (3.2.0)
+ rouge (3.2.1)
rqrcode (0.7.0)
chunky_png
rqrcode-rails3 (0.1.7)
@@ -817,7 +816,7 @@ GEM
rubyzip (1.2.1)
rufus-scheduler (3.4.0)
et-orbi (~> 1.0)
- rugged (0.27.2)
+ rugged (0.27.4)
safe_yaml (1.0.4)
sanitize (4.6.6)
crass (~> 1.0.2)
@@ -878,7 +877,6 @@ GEM
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slack-notifier (1.5.1)
- slop (3.6.0)
spring (2.0.1)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index e34db893989..5b0c4285339 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -109,8 +109,6 @@ export class AwardsHandler {
}
const $menu = $(`.${this.menuClass}`);
- const $thumbsBtn = $menu.find('[data-name="thumbsup"], [data-name="thumbsdown"]').parent();
- const $userAuthored = this.isUserAuthored($addBtn);
if ($menu.length) {
if ($menu.is('.is-visible')) {
$addBtn.removeClass('is-active');
@@ -134,9 +132,6 @@ export class AwardsHandler {
}, 200);
});
}
-
- $thumbsBtn.toggleClass('disabled', $userAuthored);
- $thumbsBtn.prop('disabled', $userAuthored);
}
// Create the emoji menu with the first category of emojis.
@@ -364,10 +359,6 @@ export class AwardsHandler {
return $emojiButton.hasClass('active');
}
- isUserAuthored($button) {
- return $button.hasClass('js-user-authored');
- }
-
decrementCounter($emojiButton, emoji) {
const counter = $('.js-counter', $emojiButton);
const counterNumber = parseInt(counter.text(), 10);
@@ -474,20 +465,16 @@ export class AwardsHandler {
}
postEmoji($emojiButton, awardUrl, emoji, callback) {
- if (this.isUserAuthored($emojiButton)) {
- this.userAuthored($emojiButton);
- } else {
- axios
- .post(awardUrl, {
- name: emoji,
- })
- .then(({ data }) => {
- if (data.ok) {
- callback();
- }
- })
- .catch(() => flash(__('Something went wrong on our end.')));
- }
+ axios
+ .post(awardUrl, {
+ name: emoji,
+ })
+ .then(({ data }) => {
+ if (data.ok) {
+ callback();
+ }
+ })
+ .catch(() => flash(__('Something went wrong on our end.')));
}
findEmojiIcon(votesBlock, emoji) {
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 56a8d9430c7..0347f803757 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -146,13 +146,7 @@ export default {
staged: false,
prevPath: '',
moved: false,
- lastCommit: Object.assign(state.entries[file.path].lastCommit, {
- id: lastCommit.commit.id,
- url: lastCommit.commit_path,
- message: lastCommit.commit.message,
- author: lastCommit.commit.author_name,
- updatedAt: lastCommit.commit.authored_date,
- }),
+ lastCommitSha: lastCommit.commit.id,
});
if (prevPath) {
diff --git a/app/assets/javascripts/jobs/components/environments_block.vue b/app/assets/javascripts/jobs/components/environments_block.vue
new file mode 100644
index 00000000000..ca6386595c7
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/environments_block.vue
@@ -0,0 +1,118 @@
+<script>
+ import _ from 'underscore';
+ import CiIcon from '~/vue_shared/components/ci_icon.vue';
+ import { sprintf, __ } from '../../locale';
+
+ export default {
+ components: {
+ CiIcon,
+ },
+ props: {
+ deploymentStatus: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ environment() {
+ let environmentText;
+ switch (this.deploymentStatus.status) {
+ case 'latest':
+ environmentText = sprintf(
+ __('This job is the most recent deployment to %{link}.'),
+ { link: this.environmentLink },
+ false,
+ );
+ break;
+ case 'out_of_date':
+ if (this.hasLastDeployment) {
+ environmentText = sprintf(
+ __(
+ 'This job is an out-of-date deployment to %{environmentLink}. View the most recent deployment %{deploymentLink}.',
+ ),
+ {
+ environmentLink: this.environmentLink,
+ deploymentLink: this.deploymentLink,
+ },
+ false,
+ );
+ } else {
+ environmentText = sprintf(
+ __('This job is an out-of-date deployment to %{environmentLink}.'),
+ { environmentLink: this.environmentLink },
+ false,
+ );
+ }
+
+ break;
+ case 'failed':
+ environmentText = sprintf(
+ __('The deployment of this job to %{environmentLink} did not succeed.'),
+ { environmentLink: this.environmentLink },
+ false,
+ );
+ break;
+ case 'creating':
+ if (this.hasLastDeployment) {
+ environmentText = sprintf(
+ __(
+ 'This job is creating a deployment to %{environmentLink} and will overwrite the last %{deploymentLink}.',
+ ),
+ {
+ environmentLink: this.environmentLink,
+ deploymentLink: this.deploymentLink,
+ },
+ false,
+ );
+ } else {
+ environmentText = sprintf(
+ __('This job is creating a deployment to %{environmentLink}.'),
+ { environmentLink: this.environmentLink },
+ false,
+ );
+ }
+ break;
+ default:
+ break;
+ }
+ return environmentText;
+ },
+ environmentLink() {
+ return sprintf(
+ '%{startLink}%{name}%{endLink}',
+ {
+ startLink: `<a href="${this.deploymentStatus.environment.path}">`,
+ name: _.escape(this.deploymentStatus.environment.name),
+ endLink: '</a>',
+ },
+ false,
+ );
+ },
+ deploymentLink() {
+ return sprintf(
+ '%{startLink}%{name}%{endLink}',
+ {
+ startLink: `<a href="${this.lastDeployment.path}">`,
+ name: _.escape(this.lastDeployment.name),
+ endLink: '</a>',
+ },
+ false,
+ );
+ },
+ hasLastDeployment() {
+ return this.deploymentStatus.environment.last_deployment;
+ },
+ lastDeployment() {
+ return this.deploymentStatus.environment.last_deployment;
+ },
+ },
+ };
+</script>
+<template>
+ <div class="prepend-top-default js-environment-container">
+ <div class="environment-information">
+ <ci-icon :status="deploymentStatus.icon" />
+ <p v-html="environment"></p>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index 225d9f18612..e111d3b9ac2 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -82,29 +82,17 @@ export default {
getAwardHTML(name) {
return glEmojiTag(name);
},
- getAwardClassBindings(awardList, awardName) {
+ getAwardClassBindings(awardList) {
return {
active: this.hasReactionByCurrentUser(awardList),
- disabled: !this.canInteractWithEmoji(awardList, awardName),
+ disabled: !this.canInteractWithEmoji(),
};
},
- canInteractWithEmoji(awardList, awardName) {
- let isAllowed = true;
- const restrictedEmojis = ['thumbsup', 'thumbsdown'];
-
- // Users can not add :+1: and :-1: to their own notes
- if (
- this.getUserData.id === this.noteAuthorId &&
- restrictedEmojis.indexOf(awardName) > -1
- ) {
- isAllowed = false;
- }
-
- return this.getUserData.id && isAllowed;
+ canInteractWithEmoji() {
+ return this.getUserData.id;
},
hasReactionByCurrentUser(awardList) {
- return awardList.filter(award => award.user.id === this.getUserData.id)
- .length;
+ return awardList.filter(award => award.user.id === this.getUserData.id).length;
},
awardTitle(awardsList) {
const hasReactionByCurrentUser = this.hasReactionByCurrentUser(
@@ -197,7 +185,7 @@ export default {
v-tooltip
v-for="(awardList, awardName, index) in groupedAwards"
:key="index"
- :class="getAwardClassBindings(awardList, awardName)"
+ :class="getAwardClassBindings(awardList)"
:title="awardTitle(awardList)"
class="btn award-control"
data-boundary="viewport"
diff --git a/app/assets/javascripts/pages/groups/milestones/show/index.js b/app/assets/javascripts/pages/groups/milestones/show/index.js
index 74cc4ba42c1..ebaea5ef3dc 100644
--- a/app/assets/javascripts/pages/groups/milestones/show/index.js
+++ b/app/assets/javascripts/pages/groups/milestones/show/index.js
@@ -1,8 +1,10 @@
import initMilestonesShow from '~/pages/milestones/shared/init_milestones_show';
+import initDeleteMilestoneModal from '~/pages/milestones/shared/delete_milestone_modal_init';
+
import Milestone from '~/milestone';
document.addEventListener('DOMContentLoaded', () => {
initMilestonesShow();
-
+ initDeleteMilestoneModal();
Milestone.initDeprecationMessage();
});
diff --git a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
index 4061c11ba8f..48668562f09 100644
--- a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
+++ b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
@@ -40,8 +40,8 @@
if (this.issueCount === 0 && this.mergeRequestCount === 0) {
return sprintf(
s__(`Milestones|
-You’re about to permanently delete the milestone %{milestoneTitle} from this project.
-%{milestoneTitle} is not currently used in any issues or merge requests.`),
+You’re about to permanently delete the milestone %{milestoneTitle}.
+This milestone is not currently used in any issues or merge requests.`),
{
milestoneTitle,
},
@@ -51,7 +51,7 @@ You’re about to permanently delete the milestone %{milestoneTitle} from this p
return sprintf(
s__(`Milestones|
-You’re about to permanently delete the milestone %{milestoneTitle} from this project and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}.
+You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}.
Once deleted, it cannot be undone or recovered.`),
{
milestoneTitle,
diff --git a/app/assets/javascripts/pages/profiles/show/index.js b/app/assets/javascripts/pages/profiles/show/index.js
index 949219a0837..aea7b649c20 100644
--- a/app/assets/javascripts/pages/profiles/show/index.js
+++ b/app/assets/javascripts/pages/profiles/show/index.js
@@ -3,15 +3,22 @@ import createFlash from '~/flash';
import GfmAutoComplete from '~/gfm_auto_complete';
import EmojiMenu from './emoji_menu';
+const defaultStatusEmoji = 'speech_balloon';
+
document.addEventListener('DOMContentLoaded', () => {
const toggleEmojiMenuButtonSelector = '.js-toggle-emoji-menu';
const toggleEmojiMenuButton = document.querySelector(toggleEmojiMenuButtonSelector);
const statusEmojiField = document.getElementById('js-status-emoji-field');
const statusMessageField = document.getElementById('js-status-message-field');
- const findNoEmojiPlaceholder = () => document.getElementById('js-no-emoji-placeholder');
+ const toggleNoEmojiPlaceholder = (isVisible) => {
+ const placeholderElement = document.getElementById('js-no-emoji-placeholder');
+ placeholderElement.classList.toggle('hidden', !isVisible);
+ };
+
+ const findStatusEmoji = () => toggleEmojiMenuButton.querySelector('gl-emoji');
const removeStatusEmoji = () => {
- const statusEmoji = toggleEmojiMenuButton.querySelector('gl-emoji');
+ const statusEmoji = findStatusEmoji();
if (statusEmoji) {
statusEmoji.remove();
}
@@ -19,7 +26,7 @@ document.addEventListener('DOMContentLoaded', () => {
const selectEmojiCallback = (emoji, emojiTag) => {
statusEmojiField.value = emoji;
- findNoEmojiPlaceholder().classList.add('hidden');
+ toggleNoEmojiPlaceholder(false);
removeStatusEmoji();
toggleEmojiMenuButton.innerHTML += emojiTag;
};
@@ -29,7 +36,7 @@ document.addEventListener('DOMContentLoaded', () => {
statusEmojiField.value = '';
statusMessageField.value = '';
removeStatusEmoji();
- findNoEmojiPlaceholder().classList.remove('hidden');
+ toggleNoEmojiPlaceholder(true);
});
const emojiAutocomplete = new GfmAutoComplete();
@@ -44,6 +51,23 @@ document.addEventListener('DOMContentLoaded', () => {
selectEmojiCallback,
);
emojiMenu.bindEvents();
+
+ const defaultEmojiTag = Emoji.glEmojiTag(defaultStatusEmoji);
+ statusMessageField.addEventListener('input', () => {
+ const hasStatusMessage = statusMessageField.value.trim() !== '';
+ const statusEmoji = findStatusEmoji();
+ if (hasStatusMessage && statusEmoji) {
+ return;
+ }
+
+ if (hasStatusMessage) {
+ toggleNoEmojiPlaceholder(false);
+ toggleEmojiMenuButton.innerHTML += defaultEmojiTag;
+ } else if (statusEmoji.dataset.name === defaultStatusEmoji) {
+ toggleNoEmojiPlaceholder(true);
+ removeStatusEmoji();
+ }
+ });
})
.catch(() => createFlash('Failed to load emoji list!'));
});
diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js
index 41880d27516..6e5ef0ac0b2 100644
--- a/app/assets/javascripts/performance_bar/index.js
+++ b/app/assets/javascripts/performance_bar/index.js
@@ -1,5 +1,4 @@
import Vue from 'vue';
-import Flash from '../flash';
import PerformanceBarService from './services/performance_bar_service';
import PerformanceBarStore from './stores/performance_bar_store';
@@ -46,7 +45,8 @@ export default ({ container }) =>
this.store.addRequestDetails(requestId, res.data.data);
})
.catch(() =>
- Flash(`Error getting performance bar results for ${requestId}`),
+ // eslint-disable-next-line no-console
+ console.warn(`Error getting performance bar results for ${requestId}`),
);
},
},
diff --git a/app/assets/javascripts/performance_bar/services/performance_bar_service.js b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
index bc71911ae35..60d9ba62570 100644
--- a/app/assets/javascripts/performance_bar/services/performance_bar_service.js
+++ b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
@@ -11,13 +11,10 @@ export default class PerformanceBarService {
static registerInterceptor(peekUrl, callback) {
const interceptor = response => {
- const requestId = response.headers['x-request-id'];
- // Get the request URL from response.config for Axios, and response for
- // Vue Resource.
- const requestUrl = (response.config || response).url;
- const cachedResponse = response.headers['x-gitlab-from-cache'] === 'true';
+ const [fireCallback, requestId, requestUrl] =
+ PerformanceBarService.callbackParams(response, peekUrl);
- if (requestUrl !== peekUrl && requestId && !cachedResponse) {
+ if (fireCallback) {
callback(requestId, requestUrl);
}
@@ -38,4 +35,16 @@ export default class PerformanceBarService {
vueResourceInterceptor,
);
}
+
+ static callbackParams(response, peekUrl) {
+ const requestId = response.headers && response.headers['x-request-id'];
+ // Get the request URL from response.config for Axios, and response for
+ // Vue Resource.
+ const requestUrl = (response.config || response).url;
+ const apiRequest = requestUrl && requestUrl.match(/^\/api\//);
+ const cachedResponse = response.headers && response.headers['x-gitlab-from-cache'] === 'true';
+ const fireCallback = requestUrl !== peekUrl && requestId && !apiRequest && !cachedResponse;
+
+ return [fireCallback, requestId, requestUrl];
+ }
}
diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
index 8487c8036ee..2ad66f4fe86 100644
--- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
@@ -1,6 +1,5 @@
<script>
import $ from 'jquery';
-import _ from 'underscore';
import JobNameComponent from './job_name_component.vue';
import JobComponent from './job_component.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
@@ -47,7 +46,7 @@ export default {
computed: {
tooltipText() {
- return _.escape(`${this.job.name} - ${this.job.status.label}`);
+ return `${this.job.name} - ${this.job.status.label}`;
},
},
diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_component.vue
index 66f95147193..9ac16b7e541 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_component.vue
@@ -1,5 +1,4 @@
<script>
-import _ from 'underscore';
import ActionComponent from './action_component.vue';
import JobNameComponent from './job_name_component.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
@@ -62,7 +61,7 @@ export default {
const textBuilder = [];
if (this.job.name) {
- textBuilder.push(_.escape(this.job.name));
+ textBuilder.push(this.job.name);
}
if (this.job.name && this.status.tooltip) {
@@ -106,7 +105,6 @@ export default {
:class="cssClassJobName"
:data-boundary="tooltipBoundary"
data-container="body"
- data-html="true"
class="js-pipeline-graph-job-link"
>
@@ -122,7 +120,6 @@ export default {
:title="tooltipText"
:class="cssClassJobName"
class="js-job-component-tooltip non-details-job-component"
- data-html="true"
data-container="body"
>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
index 21f21232596..d530ab2767b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -1,5 +1,6 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import timeagoMixin from '../../vue_shared/mixins/timeago';
import tooltip from '../../vue_shared/directives/tooltip';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
@@ -16,6 +17,7 @@ export default {
MemoryUsage,
StatusIcon,
Icon,
+ TooltipOnTruncate,
},
directives: {
tooltip,
@@ -88,14 +90,20 @@ export default {
<span>
Deployed to
</span>
- <a
- :href="deployment.url"
- target="_blank"
- rel="noopener noreferrer nofollow"
- class="deploy-link js-deploy-meta"
+ <tooltip-on-truncate
+ :title="deployment.name"
+ truncate-target="child"
+ class="deploy-link label-truncate"
>
- {{ deployment.name }}
- </a>
+ <a
+ :href="deployment.url"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="js-deploy-meta"
+ >
+ {{ deployment.name }}
+ </a>
+ </tooltip-on-truncate>
</template>
<span
v-tooltip
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
index a4c2289c590..72bd28ae03f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
@@ -1,18 +1,17 @@
<script>
-import tooltip from '~/vue_shared/directives/tooltip';
-import { n__ } from '~/locale';
+import _ from 'underscore';
+import { n__, s__, sprintf } from '~/locale';
import { mergeUrlParams, webIDEUrl } from '~/lib/utils/url_utility';
import Icon from '~/vue_shared/components/icon.vue';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
export default {
name: 'MRWidgetHeader',
- directives: {
- tooltip,
- },
components: {
Icon,
clipboardButton,
+ TooltipOnTruncate,
},
props: {
mr: {
@@ -24,8 +23,12 @@ export default {
shouldShowCommitsBehindText() {
return this.mr.divergedCommitsCount > 0;
},
- commitsText() {
- return n__('%d commit behind', '%d commits behind', this.mr.divergedCommitsCount);
+ commitsBehindText() {
+ return sprintf(s__('mrWidget|The source branch is %{commitsBehindLinkStart}%{commitsBehind}%{commitsBehindLinkEnd} the target branch'), {
+ commitsBehindLinkStart: `<a href="${_.escape(this.mr.targetBranchPath)}">`,
+ commitsBehind: n__('%d commit behind', '%d commits behind', this.mr.divergedCommitsCount),
+ commitsBehindLinkEnd: '</a>',
+ }, false);
},
branchNameClipboardData() {
// This supports code in app/assets/javascripts/copy_to_clipboard.js that
@@ -36,12 +39,6 @@ export default {
gfm: `\`${this.mr.sourceBranch}\``,
});
},
- isSourceBranchLong() {
- return this.isBranchTitleLong(this.mr.sourceBranch);
- },
- isTargetBranchLong() {
- return this.isBranchTitleLong(this.mr.targetBranch);
- },
webIdePath() {
return mergeUrlParams({
target_project: this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath ?
@@ -49,11 +46,6 @@ export default {
}, webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`));
},
},
- methods: {
- isBranchTitleLong(branchTitle) {
- return branchTitle.length > 32;
- },
- },
};
</script>
<template>
@@ -65,30 +57,21 @@ export default {
<div class="normal">
<strong>
{{ s__("mrWidget|Request to merge") }}
- <span
- :class="{ 'label-truncated': isSourceBranchLong }"
- :title="isSourceBranchLong ? mr.sourceBranch : ''"
- :v-tooltip="isSourceBranchLong"
- class="label-branch js-source-branch"
- data-placement="bottom"
+ <tooltip-on-truncate
+ :title="mr.sourceBranch"
+ truncate-target="child"
+ class="label-branch label-truncate js-source-branch"
v-html="mr.sourceBranchLink"
- >
- </span>
-
- <clipboard-button
+ /><clipboard-button
:text="branchNameClipboardData"
:title="__('Copy branch name to clipboard')"
css-class="btn-default btn-transparent btn-clipboard"
/>
-
{{ s__("mrWidget|into") }}
-
- <span
- :v-tooltip="isTargetBranchLong"
- :class="{ 'label-truncatedtooltip': isTargetBranchLong }"
- :title="isTargetBranchLong ? mr.targetBranch : ''"
- class="label-branch"
- data-placement="bottom"
+ <tooltip-on-truncate
+ :title="mr.targetBranch"
+ truncate-target="child"
+ class="label-branch label-truncate"
>
<a
:href="mr.targetBranchTreePath"
@@ -96,15 +79,13 @@ export default {
>
{{ mr.targetBranch }}
</a>
- </span>
+ </tooltip-on-truncate>
</strong>
<div
v-if="shouldShowCommitsBehindText"
class="diverged-commits-count"
+ v-html="commitsBehindText"
>
- <span class="monospace">{{ mr.sourceBranch }}</span>
- is {{ commitsText }}
- <span class="monospace">{{ mr.targetBranch }}</span>
</div>
</div>
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 4a3fd01fa39..fee41b239e8 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
@@ -3,6 +3,7 @@
import PipelineStage from '~/pipelines/components/stage.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
export default {
name: 'MRWidgetPipeline',
@@ -10,6 +11,7 @@ export default {
PipelineStage,
CiIcon,
Icon,
+ TooltipOnTruncate,
},
props: {
pipeline: {
@@ -30,6 +32,10 @@ export default {
type: String,
required: false,
},
+ sourceBranch: {
+ type: String,
+ required: false,
+ },
},
computed: {
hasPipeline() {
@@ -107,11 +113,12 @@ export default {
>
{{ pipeline.commit.short_id }}</a>
on
- <span
- class="label-branch"
+ <tooltip-on-truncate
+ :title="sourceBranch"
+ truncate-target="child"
+ class="label-branch label-truncate"
v-html="sourceBranchLink"
- >
- </span>
+ />
</template>
</div>
<div
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 80593d1f34a..dc6be025f11 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -254,6 +254,7 @@ export default {
:pipeline="mr.pipeline"
:ci-status="mr.ciStatus"
:has-ci="mr.hasCI"
+ :source-branch="mr.sourceBranch"
:source-branch-link="mr.sourceBranchLink"
/>
<deployment
diff --git a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
index f44d361c47e..78fde463507 100644
--- a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
@@ -71,7 +71,11 @@ export default {
},
methods: {
getPercent(count) {
- return roundOffFloat((count / this.totalCount) * 100, 1);
+ const percent = roundOffFloat((count / this.totalCount) * 100, 1);
+ if (percent > 0 && percent < 1) {
+ return '< 1';
+ }
+ return percent;
},
barStyle(percent) {
return `width: ${percent}%;`;
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
new file mode 100644
index 00000000000..125826da6c3
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
@@ -0,0 +1,67 @@
+<script>
+import _ from 'underscore';
+import tooltip from '../directives/tooltip';
+
+export default {
+ directives: {
+ tooltip,
+ },
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ placement: {
+ type: String,
+ required: false,
+ default: 'top',
+ },
+ truncateTarget: {
+ type: [String, Function],
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ showTooltip: false,
+ };
+ },
+ mounted() {
+ const target = this.selectTarget();
+
+ if (target && target.scrollWidth > target.offsetWidth) {
+ this.showTooltip = true;
+ }
+ },
+ methods: {
+ selectTarget() {
+ if (_.isFunction(this.truncateTarget)) {
+ return this.truncateTarget(this.$el);
+ } else if (this.truncateTarget === 'child') {
+ return this.$el.childNodes[0];
+ }
+
+ return this.$el;
+ },
+ },
+};
+</script>
+
+<template>
+ <span
+ v-tooltip
+ v-if="showTooltip"
+ :title="title"
+ :data-placement="placement"
+ class="js-show-tooltip"
+ >
+ <slot></slot>
+ </span>
+ <span
+ v-else
+ >
+ <slot></slot>
+ </span>
+</template>
diff --git a/app/assets/stylesheets/framework/callout.scss b/app/assets/stylesheets/framework/callout.scss
index 1bd94c0acba..bdd7f09d926 100644
--- a/app/assets/stylesheets/framework/callout.scss
+++ b/app/assets/stylesheets/framework/callout.scss
@@ -25,25 +25,25 @@
/* Variations */
.bs-callout-danger {
- background-color: $callout-danger-bg;
- border-color: $callout-danger-border;
- color: $callout-danger-color;
+ background-color: $red-100;
+ border-color: $red-200;
+ color: $red-700;
}
.bs-callout-warning {
- background-color: $callout-warning-bg;
- border-color: $callout-warning-border;
- color: $callout-warning-color;
+ background-color: $orange-100;
+ border-color: $orange-200;
+ color: $orange-700;
}
.bs-callout-info {
- background-color: $callout-info-bg;
- border-color: $callout-info-border;
- color: $callout-info-color;
+ background-color: $blue-100;
+ border-color: $blue-200;
+ color: $blue-700;
}
.bs-callout-success {
- background-color: $callout-success-bg;
- border-color: $callout-success-border;
- color: $callout-success-color;
+ background-color: $green-100;
+ border-color: $green-200;
+ color: $green-700;
}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 7c5380a90f7..72e27f9ad16 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -1,8 +1,8 @@
/** COLORS **/
-.cgray { color: $common-gray; }
+.cgray { color: $gl-text-color; }
.clgray { color: $common-gray-light; }
-.cred { color: $common-red; }
-.cgreen { color: $common-green; }
+.cred { color: $red-500; }
+.cgreen { color: $green-600; }
.cdark { color: $common-gray-dark; }
.text-plain,
@@ -44,10 +44,10 @@
}
.hint { font-style: italic; color: $hint-color; }
-.light { color: $common-gray; }
+.light { color: $gl-text-color; }
.slead {
- color: $common-gray;
+ color: $gl-text-color;
font-size: 14px;
margin-bottom: 12px;
font-weight: $gl-font-weight-normal;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 83bc3776178..8a224dc517e 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -147,7 +147,7 @@
}
@mixin dropdown-item-hover {
- background-color: $dropdown-item-hover-bg;
+ background-color: $gray-darker;
color: $gl-text-color;
outline: 0;
@@ -195,7 +195,7 @@
text-decoration: none;
.badge.badge-pill {
- background-color: darken($dropdown-link-hover-bg, 5%);
+ background-color: darken($blue-50, 5%);
}
}
@@ -233,7 +233,7 @@
font-weight: $gl-font-weight-normal;
padding: 8px 0;
background-color: $white-light;
- border: 1px solid $dropdown-border-color;
+ border: 1px solid $border-color;
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
@@ -874,7 +874,7 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu {
overflow-y: auto;
li.section-empty.section-failure {
- color: $callout-danger-color;
+ color: $red-700;
}
.frequent-items-list-item-container a {
diff --git a/app/assets/stylesheets/framework/emojis.scss b/app/assets/stylesheets/framework/emojis.scss
index a8ec1e1145a..6c50ea719d3 100644
--- a/app/assets/stylesheets/framework/emojis.scss
+++ b/app/assets/stylesheets/framework/emojis.scss
@@ -3,6 +3,6 @@ gl-emoji {
display: inline-flex;
vertical-align: middle;
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- font-size: 1.5em;
- line-height: 0.9;
+ font-size: 1.4em;
+ line-height: 1em;
}
diff --git a/app/assets/stylesheets/framework/feature_highlight.scss b/app/assets/stylesheets/framework/feature_highlight.scss
index cad915bc86f..85cabf43e9e 100644
--- a/app/assets/stylesheets/framework/feature_highlight.scss
+++ b/app/assets/stylesheets/framework/feature_highlight.scss
@@ -72,11 +72,11 @@
.feature-highlight-popover {
width: 240px;
padding: 0;
- border: 1px solid $dropdown-border-color;
+ border: 1px solid $border-color;
box-shadow: 0 2px 4px $dropdown-shadow-color;
&.right > .arrow {
- border-right-color: $dropdown-border-color;
+ border-right-color: $border-color;
}
.popover-body {
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 3bdf5bfc93a..1d3512bbb4c 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -312,11 +312,11 @@ span.idiff {
text-decoration: none;
.new-file {
- color: $notify-new-file;
+ color: $green-600;
}
.deleted-file {
- color: $notify-deleted-file;
+ color: $red-700;
}
}
}
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index a70eece8f68..afd888af672 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -8,7 +8,7 @@ input {
input[type='text'].danger {
background: $input-danger-bg !important;
- border-color: $input-danger-border;
+ border-color: $red-400;
text-shadow: 0 1px 1px $white-light;
}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 88d2f0aaf85..3ae2c7078d6 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -58,7 +58,7 @@
.select2-drop.select2-drop-above {
box-shadow: 0 2px 4px $dropdown-shadow-color;
border-radius: $border-radius-base;
- border: 1px solid $dropdown-border-color;
+ border: 1px solid $border-color;
min-width: 175px;
color: $gl-text-color;
z-index: 999;
@@ -69,7 +69,7 @@
}
.select2-drop.select2-drop-above.select2-drop-active {
- border-top: 1px solid $dropdown-border-color;
+ border-top: 1px solid $border-color;
margin-top: -6px;
}
@@ -193,7 +193,7 @@
color: $gl-text-color;
.select2-result-label {
- background: $dropdown-item-hover-bg;
+ background: $gray-darker;
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 3531ce31794..2781d910b8d 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -319,7 +319,6 @@ $line-select-yellow-dark: #f0e2bd;
$dark-diff-match-bg: rgba(255, 255, 255, 0.3);
$dark-diff-match-color: rgba(255, 255, 255, 0.1);
$file-mode-changed: #777;
-$file-mode-changed: #777;
$diff-image-info-color: gray;
$diff-swipe-border: #999;
$diff-view-modes-color: gray;
@@ -342,9 +341,7 @@ $dropdown-min-height: 40px;
$dropdown-max-height: 312px;
$dropdown-vertical-offset: 4px;
$dropdown-link-color: #555;
-$dropdown-link-hover-bg: $blue-50;
$dropdown-empty-row-bg: rgba(#000, 0.04);
-$dropdown-border-color: $border-color;
$dropdown-shadow-color: rgba(#000, 0.1);
$dropdown-divider-color: rgba(#000, 0.1);
$dropdown-title-btn-color: #bfbfbf;
@@ -354,7 +351,6 @@ $dropdown-input-focus-shadow: rgba($blue-300, 0.4);
$dropdown-loading-bg: rgba(#fff, 0.6);
$dropdown-chevron-size: 10px;
$dropdown-toggle-active-border-color: darken($border-color, 14%);
-$dropdown-item-hover-bg: $gray-darker;
$dropdown-fade-mask-height: 32px;
$dropdown-member-form-control-width: 163px;
@@ -496,22 +492,6 @@ $blame-blue: #254e77;
$builds-trace-bg: #111;
/*
-* Callout
-*/
-$callout-danger-bg: $red-100;
-$callout-danger-border: $red-200;
-$callout-danger-color: $red-700;
-$callout-warning-bg: $orange-100;
-$callout-warning-border: $orange-200;
-$callout-warning-color: $orange-700;
-$callout-info-bg: $blue-100;
-$callout-info-border: $blue-200;
-$callout-info-color: $blue-700;
-$callout-success-bg: $green-100;
-$callout-success-border: $green-200;
-$callout-success-color: $green-700;
-
-/*
* Commit Page
*/
$commit-max-width-marker-color: rgba(0, 0, 0, 0);
@@ -520,16 +500,8 @@ $commit-message-text-area-bg: rgba(0, 0, 0, 0);
/*
* Common
*/
-$common-gray: $gl-text-color;
$common-gray-light: #bbb;
$common-gray-dark: #444;
-$common-red: $red-500;
-$common-green: $green-600;
-
-/*
-* Editor
-*/
-$editor-cancel-color: $red-600;
/*
* Events
@@ -550,7 +522,6 @@ $logs-p-color: #333;
*/
$input-height: 34px;
$input-danger-bg: #f2dede;
-$input-danger-border: $red-400;
$input-group-addon-bg: #f7f8fa;
$gl-field-focus-shadow: rgba(0, 0, 0, 0.075);
$gl-field-focus-shadow-error: rgba($red-500, 0.6);
@@ -597,16 +568,9 @@ $fade-mask-transition-duration: 0.1s;
$fade-mask-transition-curve: ease-in-out;
/*
-* Lint
-*/
-$lint-incorrect-color: $red-500;
-$lint-correct-color: $green-500;
-
-/*
* Login
*/
$login-brand-holder-color: #888;
-$login-devise-error-color: $red-700;
/*
* Nav
@@ -619,15 +583,12 @@ $nav-toggle-gray: #666;
*/
$notify-details: #777;
$notify-footer: #777;
-$notify-new-file: $green-600;
-$notify-deleted-file: $red-700;
/*
* Projects
*/
$project-option-descr-color: #54565b;
$project-breadcrumb-color: #999;
-$project-private-forks-notice-odd: $green-600;
$project-network-controls-color: #888;
$feature-toggle-color: #fff;
@@ -636,21 +597,10 @@ $feature-toggle-color-disabled: #999;
$feature-toggle-color-enabled: #4a8bee;
/*
-* Runners
-*/
-$runner-state-shared-bg: $green-400;
-$runner-state-specific-bg: $blue-400;
-$runner-status-online-color: $green-600;
-$runner-status-offline-color: $gray-darkest;
-$runner-status-paused-color: $red-500;
-
-/*
Stat Graph
*/
$stat-graph-common-bg: #f3f3f3;
-$stat-graph-area-fill: $green-500;
$stat-graph-axis-fill: #aaa;
-$stat-graph-orange-fill: $orange-500;
$stat-graph-selection-fill: #333;
$stat-graph-selection-stroke: #333;
@@ -663,7 +613,6 @@ $select2-drop-shadow2: rgba(31, 37, 50, 0.317647);
/*
* Todo
*/
-$todo-alert-blue: $blue-500;
$todo-body-pre-color: #777;
$todo-body-border: #ddd;
@@ -686,7 +635,6 @@ $ui-dev-kit-example-border: #ddd;
/*
Pipeline Graph
*/
-$stage-hover-bg: $gray-darker;
$ci-action-icon-size: 22px;
$ci-action-icon-size-lg: 24px;
$pipeline-dropdown-line-height: 20px;
@@ -714,13 +662,6 @@ Animation Functions
$dropdown-animation-timing: cubic-bezier(0.23, 1, 0.32, 1);
/*
-Convdev Index
-*/
-$color-high-score: $green-400;
-$color-average-score: $orange-400;
-$color-low-score: $red-400;
-
-/*
Performance Bar
*/
$perf-bar-text: #999;
@@ -761,9 +702,5 @@ Modals
*/
$modal-body-height: 134px;
-/*
-Prometheus
-*/
-$prometheus-table-row-highlight-color: $theme-gray-100;
$priority-label-empty-state-width: 114px;
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 1696d18584d..14ba8b1df83 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -397,7 +397,7 @@
}
&:hover {
- background-color: $dropdown-item-hover-bg;
+ background-color: $gray-darker;
}
.icon-retry {
diff --git a/app/assets/stylesheets/pages/convdev_index.scss b/app/assets/stylesheets/pages/convdev_index.scss
index bd338326154..52fcdf4a405 100644
--- a/app/assets/stylesheets/pages/convdev_index.scss
+++ b/app/assets/stylesheets/pages/convdev_index.scss
@@ -80,7 +80,7 @@ $space-between-cards: 8px;
}
.convdev-card-low {
- border-top-color: $color-low-score;
+ border-top-color: $red-400;
.board-card-score-big {
background-color: $red-50;
@@ -88,7 +88,7 @@ $space-between-cards: 8px;
}
.convdev-card-average {
- border-top-color: $color-average-score;
+ border-top-color: $orange-400;
.board-card-score-big {
background-color: $orange-50;
@@ -96,7 +96,7 @@ $space-between-cards: 8px;
}
.convdev-card-high {
- border-top-color: $color-high-score;
+ border-top-color: $green-400;
.board-card-score-big {
background-color: $green-50;
@@ -243,13 +243,13 @@ $space-between-cards: 8px;
}
.convdev-high-score {
- color: $color-high-score;
+ color: $green-400;
}
.convdev-average-score {
- color: $color-average-score;
+ color: $orange-400;
}
.convdev-low-score {
- color: $color-low-score;
+ color: $red-400;
}
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 892da152b5f..04570c057d1 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -23,10 +23,10 @@
}
.cancel-btn {
- color: $editor-cancel-color;
+ color: $red-600;
&:hover {
- color: $editor-cancel-color;
+ color: $red-600;
}
}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 179c0964567..196f6ae6d8c 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -501,5 +501,5 @@
}
.prometheus-table-row-highlight {
- background-color: $prometheus-table-row-highlight-color;
+ background-color: $theme-gray-100;
}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index 8a4a2caa6c9..c9e5fb9c579 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -186,7 +186,7 @@
h2 {
margin-top: 0;
font-size: 14px;
- color: $login-devise-error-color;
+ color: $red-700;
}
}
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 5631d943984..7b8cad254c7 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -195,6 +195,7 @@
.ci-widget-content {
display: flex;
align-items: center;
+ flex: 1;
}
}
@@ -222,6 +223,7 @@
.normal {
flex: 1;
+ flex-basis: auto;
}
.capitalize {
@@ -235,22 +237,23 @@
font-weight: normal;
overflow: hidden;
word-break: break-all;
+ }
- &.label-truncated {
- position: relative;
- display: inline-block;
- width: 250px;
- margin-bottom: -3px;
- white-space: nowrap;
- text-overflow: clip;
- line-height: 14px;
-
- &::after {
- position: absolute;
- content: '...';
- right: 0;
- font-family: $regular-font;
- background-color: $gray-light;
+ .deploy-link,
+ .label-branch {
+ &.label-truncate {
+ // NOTE: This selector targets its children because some of the HTML comes from
+ // 'source_branch_link'. Once this external HTML is no longer used, we could
+ // simplify this.
+ > a,
+ > span {
+ display: inline-block;
+ max-width: 12.5em;
+ margin-bottom: -3px;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ line-height: 14px;
+ overflow: hidden;
}
}
}
@@ -582,7 +585,7 @@
@include media-breakpoint-down(md) {
flex-direction: column;
- align-items: flex-start;
+ align-items: stretch;
.branch-actions {
margin-top: 16px;
@@ -593,13 +596,13 @@
.branch-actions {
align-self: center;
margin-left: $gl-padding;
+ white-space: nowrap;
}
}
}
.diverged-commits-count {
color: $gl-text-color-secondary;
- font-size: 12px;
}
}
@@ -918,7 +921,7 @@
flex: 1;
flex-direction: row;
- @include media-breakpoint-down(md) {
+ @include media-breakpoint-down(sm) {
flex-direction: column;
.stage-cell .stage-container {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index fce04c58c24..dbe9f0c03fb 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -141,6 +141,9 @@ ul.notes {
}
.note-body {
+ overflow-x: auto;
+ overflow-y: hidden;
+
.note-text {
@include md-typography;
// Reset ul style types since we're nested inside a ul already
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index ad057ed3c83..8bb8b83dc5e 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -19,7 +19,7 @@
background-color: $white-light;
&:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
color: $gl-text-color;
}
@@ -595,7 +595,7 @@
a.build-content:hover,
button.build-content:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
}
@@ -668,7 +668,7 @@
display: block;
&:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
svg {
@@ -835,7 +835,7 @@ button.mini-pipeline-graph-dropdown-toggle {
display: block;
&:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
svg {
@@ -934,7 +934,7 @@ button.mini-pipeline-graph-dropdown-toggle {
&:focus {
outline: none;
text-decoration: none;
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
}
}
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 3154bcf5d0f..a95e78931b1 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -900,7 +900,7 @@ pre.light-well {
.private-forks-notice .private-fork-icon {
i:nth-child(1) {
- color: $project-private-forks-notice-odd;
+ color: $green-600;
}
i:nth-child(2) {
@@ -1128,12 +1128,12 @@ pre.light-well {
.project-ci-body {
.incorrect-syntax {
font-size: 18px;
- color: $lint-incorrect-color;
+ color: $red-500;
}
.correct-syntax {
font-size: 18px;
- color: $lint-correct-color;
+ color: $green-500;
}
}
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
index 2734faec558..59f01f3e958 100644
--- a/app/assets/stylesheets/pages/runners.scss
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -4,24 +4,24 @@
color: $white-light;
&.runner-state-shared {
- background: $runner-state-shared-bg;
+ background: $green-400;
}
&.runner-state-specific {
- background: $runner-state-specific-bg;
+ background: $blue-400;
}
}
.runner-status-online {
- color: $runner-status-online-color;
+ color: $green-600;
}
.runner-status-offline {
- color: $runner-status-offline-color;
+ color: $gray-darkest;
}
.runner-status-paused {
- color: $runner-status-paused-color;
+ color: $red-500;
}
.runner {
diff --git a/app/assets/stylesheets/pages/stat_graph.scss b/app/assets/stylesheets/pages/stat_graph.scss
index 3f6f5f06075..d331edaa302 100644
--- a/app/assets/stylesheets/pages/stat_graph.scss
+++ b/app/assets/stylesheets/pages/stat_graph.scss
@@ -5,7 +5,7 @@
}
.area {
- fill: $stat-graph-area-fill;
+ fill: $green-500;
fill-opacity: 0.5;
}
@@ -54,7 +54,7 @@
}
.area-contributor {
- fill: $stat-graph-orange-fill;
+ fill: $orange-500;
}
}
}
diff --git a/app/controllers/concerns/renders_commits.rb b/app/controllers/concerns/renders_commits.rb
index fb41dc1e8a8..b1c9b1e532f 100644
--- a/app/controllers/concerns/renders_commits.rb
+++ b/app/controllers/concerns/renders_commits.rb
@@ -1,4 +1,24 @@
module RendersCommits
+ def limited_commits(commits)
+ if commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ [
+ commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE),
+ commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE
+ ]
+ else
+ [commits, 0]
+ end
+ end
+
+ # This is used as a helper method in a controller.
+ # rubocop: disable Gitlab/ModuleWithInstanceVariables
+ def set_commits_for_rendering(commits)
+ @total_commit_count = commits.size
+ limited, @hidden_commit_count = limited_commits(commits)
+ prepare_commits_for_rendering(limited)
+ end
+ # rubocop: enable Gitlab/ModuleWithInstanceVariables
+
def prepare_commits_for_rendering(commits)
Banzai::CommitRenderer.render(commits, @project, current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables
diff --git a/app/controllers/concerns/toggle_award_emoji.rb b/app/controllers/concerns/toggle_award_emoji.rb
index ba5b7d33f87..ae0b815f85e 100644
--- a/app/controllers/concerns/toggle_award_emoji.rb
+++ b/app/controllers/concerns/toggle_award_emoji.rb
@@ -5,7 +5,7 @@ module ToggleAwardEmoji
authenticate_user!
name = params.require(:name)
- if awardable.user_can_award?(current_user, name)
+ if awardable.user_can_award?(current_user)
awardable.toggle_award_emoji(name, current_user)
todoable = to_todoable(awardable)
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 9bd51de7e97..6bdc0f79ef2 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -2,8 +2,8 @@ class Groups::MilestonesController < Groups::ApplicationController
include MilestoneActions
before_action :group_projects
- before_action :milestone, only: [:edit, :show, :update, :merge_requests, :participants, :labels]
- before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update]
+ before_action :milestone, only: [:edit, :show, :update, :merge_requests, :participants, :labels, :destroy]
+ before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update, :destroy]
def index
respond_to do |format|
@@ -56,10 +56,21 @@ class Groups::MilestonesController < Groups::ApplicationController
redirect_to milestone_path
end
+ def destroy
+ return render_404 if @milestone.legacy_group_milestone?
+
+ Milestones::DestroyService.new(group, current_user).execute(@milestone)
+
+ respond_to do |format|
+ format.html { redirect_to group_milestones_path(group), status: :see_other }
+ format.js { head :ok }
+ end
+ end
+
private
def authorize_admin_milestones!
- return render_404 unless can?(current_user, :admin_milestones, group)
+ return render_404 unless can?(current_user, :admin_milestone, group)
end
def milestone_params
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 36faea8056e..5546bef850b 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -63,7 +63,7 @@ class Projects::CommitsController < Projects::ApplicationController
end
@commits = @commits.with_pipeline_status
- @commits = prepare_commits_for_rendering(@commits)
+ @commits = set_commits_for_rendering(@commits)
end
# Rails 5 sets request.format from the extension.
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index f93e500a07a..a1e12821caf 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -78,7 +78,7 @@ class Projects::CompareController < Projects::ApplicationController
end
def define_commits
- @commits = compare.present? ? prepare_commits_for_rendering(compare.commits) : []
+ @commits = compare.present? ? set_commits_for_rendering(@compare.commits) : []
end
def define_diffs
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index ef8159aa553..c3ac8e107fb 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -113,7 +113,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def referenced_merge_requests
- @merge_requests, @closed_by_merge_requests = ::Issues::FetchReferencedMergeRequestsService.new(project, current_user).execute(issue)
+ @merge_requests, @closed_by_merge_requests = ::Issues::ReferencedMergeRequestsService.new(project, current_user).execute(issue)
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 81129456ad8..03d0290ac1d 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -101,7 +101,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@target_project = @merge_request.target_project
@source_project = @merge_request.source_project
- @commits = prepare_commits_for_rendering(@merge_request.commits)
+ @commits = set_commits_for_rendering(@merge_request.commits)
@commit = @merge_request.diff_head_commit
@labels = LabelsFinder.new(current_user, project_id: @project.id).execute
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 1b069fe507b..d31b58972ca 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -79,7 +79,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
# Get commits from repository
# or from cache if already merged
@commits =
- prepare_commits_for_rendering(@merge_request.commits.with_pipeline_status)
+ set_commits_for_rendering(@merge_request.commits.with_pipeline_status)
render json: { html: view_to_html_string('projects/merge_requests/_commits') }
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 89fe90fd801..7a942c44ac4 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -210,17 +210,6 @@ module CommitsHelper
Sanitize.clean(string, remove_contents: true)
end
- def limited_commits(commits)
- if commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
- [
- commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE),
- commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE
- ]
- else
- [commits, 0]
- end
- end
-
def commit_path(project, commit, merge_request: nil)
if merge_request&.persisted?
diffs_project_merge_request_path(project, merge_request, commit_id: commit.id)
diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb
index 4664b1728c4..c65f1565425 100644
--- a/app/helpers/import_helper.rb
+++ b/app/helpers/import_helper.rb
@@ -5,6 +5,10 @@ module ImportHelper
false
end
+ def sanitize_project_name(name)
+ name.gsub(/[^\w\-]/, '-')
+ end
+
def import_project_target(owner, name)
namespace = current_user.can_create_group? ? owner : current_user.namespace_path
"#{namespace}/#{name}"
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 96dc7ae1185..5b27d1d9404 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -92,14 +92,6 @@ module IssuesHelper
end
end
- def award_user_authored_class(award)
- if award == 'thumbsdown' || award == 'thumbsup'
- 'user-authored js-user-authored'
- else
- ''
- end
- end
-
def awards_sort(awards)
awards.sort_by do |award, award_emojis|
if award == "thumbsup"
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 6b4079b4113..18b3badda8d 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -447,7 +447,7 @@ module ProjectsHelper
end
def project_permissions_panel_data(project)
- data = {
+ {
currentSettings: project_permissions_settings(project),
canChangeVisibilityLevel: can_change_visibility_level?(project, current_user),
allowedVisibilityOptions: project_allowed_visibility_levels(project),
@@ -457,8 +457,10 @@ module ProjectsHelper
lfsAvailable: Gitlab.config.lfs.enabled,
lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
}
+ end
- data.to_json.html_safe
+ def project_permissions_panel_data_json(project)
+ project_permissions_panel_data(project).to_json.html_safe
end
def project_allowed_visibility_levels(project)
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index e4aed76f611..526bf7af99b 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -649,8 +649,7 @@ module Ci
def keep_around_commits
return unless project
- project.repository.keep_around(self.sha)
- project.repository.keep_around(self.before_sha)
+ project.repository.keep_around(self.sha, self.before_sha)
end
def valid_source
diff --git a/app/models/concerns/awardable.rb b/app/models/concerns/awardable.rb
index 49981db0d80..4200253053a 100644
--- a/app/models/concerns/awardable.rb
+++ b/app/models/concerns/awardable.rb
@@ -76,12 +76,8 @@ module Awardable
true
end
- def awardable_votes?(name)
- AwardEmoji::UPVOTE_NAME == name || AwardEmoji::DOWNVOTE_NAME == name
- end
-
- def user_can_award?(current_user, name)
- awardable_by_user?(current_user, name) && Ability.allowed?(current_user, :award_emoji, self)
+ def user_can_award?(current_user)
+ Ability.allowed?(current_user, :award_emoji, self)
end
def user_authored?(current_user)
@@ -117,12 +113,4 @@ module Awardable
def normalize_name(name)
Gitlab::Emoji.normalize_emoji_name(name)
end
-
- def awardable_by_user?(current_user, name)
- if user_authored?(current_user)
- !awardable_votes?(normalize_name(name))
- else
- true
- end
- end
end
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 58d949315e0..716cf6574d3 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -191,14 +191,18 @@ class DiffNote < Note
end
def keep_around_commits
- project.repository.keep_around(self.original_position.base_sha)
- project.repository.keep_around(self.original_position.start_sha)
- project.repository.keep_around(self.original_position.head_sha)
+ shas = [
+ self.original_position.base_sha,
+ self.original_position.start_sha,
+ self.original_position.head_sha
+ ]
if self.position != self.original_position
- project.repository.keep_around(self.position.base_sha)
- project.repository.keep_around(self.position.start_sha)
- project.repository.keep_around(self.position.head_sha)
+ shas << self.position.base_sha
+ shas << self.position.start_sha
+ shas << self.position.head_sha
end
+
+ project.repository.keep_around(*shas)
end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 94cf12f3c2b..d0cd7461daa 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -170,27 +170,6 @@ class Issue < ActiveRecord::Base
"#{project.to_reference(from, full: full)}#{reference}"
end
- def referenced_merge_requests(current_user = nil)
- ext = all_references(current_user)
-
- notes_with_associations.each do |object|
- object.all_references(current_user, extractor: ext)
- end
-
- merge_requests = ext.merge_requests.sort_by(&:iid)
-
- cross_project_filter = -> (merge_requests) do
- merge_requests.select { |mr| mr.target_project == project }
- end
-
- Ability.merge_requests_readable_by_user(
- merge_requests, current_user,
- filters: {
- read_cross_project: cross_project_filter
- }
- )
- end
-
# All branches containing the current issue's ID, except for
# those with a merge request open referencing the current issue.
def related_branches(current_user)
@@ -198,7 +177,11 @@ class Issue < ActiveRecord::Base
branch =~ /\A#{iid}-(?!\d+-stable)/i
end
- branches_with_merge_request = self.referenced_merge_requests(current_user).map(&:source_branch)
+ branches_with_merge_request =
+ Issues::ReferencedMergeRequestsService
+ .new(project, current_user)
+ .referenced_merge_requests(self)
+ .map(&:source_branch)
branches_with_iid - branches_with_merge_request
end
@@ -225,26 +208,6 @@ class Issue < ActiveRecord::Base
project
end
- # From all notes on this issue, we'll select the system notes about linked
- # merge requests. Of those, the MRs closing `self` are returned.
- def closed_by_merge_requests(current_user = nil)
- return [] unless open?
-
- ext = all_references(current_user)
-
- notes.system.each do |note|
- note.all_references(current_user, extractor: ext)
- end
-
- merge_requests = ext.merge_requests.select(&:open?)
- if merge_requests.any?
- ids = MergeRequestsClosingIssues.where(merge_request_id: merge_requests.map(&:id), issue_id: id).pluck(:merge_request_id)
- merge_requests.select { |mr| mr.id.in?(ids) }
- else
- []
- end
- end
-
def moved?
!moved_to.nil?
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index d9393b4e545..bbe4f6f7969 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -314,9 +314,7 @@ class MergeRequestDiff < ActiveRecord::Base
def keep_around_commits
[repository, merge_request.source_project.repository].uniq.each do |repo|
- repo.keep_around(start_commit_sha)
- repo.keep_around(head_commit_sha)
- repo.keep_around(base_commit_sha)
+ repo.keep_around(start_commit_sha, head_commit_sha, base_commit_sha)
end
end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 8f631d7f0ed..67593c9b2fe 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -85,8 +85,7 @@ class Project < ActiveRecord::Base
after_create :create_project_feature, unless: :project_feature
after_create -> { SiteStatistic.track(STATISTICS_ATTRIBUTE) }
- before_destroy ->(project) { project.project_feature.untrack_statistics_for_deletion! }
- after_destroy -> { SiteStatistic.untrack(STATISTICS_ATTRIBUTE) }
+ before_destroy :untrack_site_statistics
after_create :create_ci_cd_settings,
unless: :ci_cd_settings,
@@ -2072,13 +2071,19 @@ class Project < ActiveRecord::Base
private
def rename_or_migrate_repository!
- if Gitlab::CurrentSettings.hashed_storage_enabled? && storage_version != LATEST_STORAGE_VERSION
+ if Gitlab::CurrentSettings.hashed_storage_enabled? &&
+ storage_upgradable? &&
+ Feature.disabled?(:skip_hashed_storage_upgrade) # kill switch in case we need to disable upgrade behavior
::Projects::HashedStorageMigrationService.new(self, full_path_was).execute
else
storage.rename_repo
end
end
+ def storage_upgradable?
+ storage_version != LATEST_STORAGE_VERSION
+ end
+
def after_rename_repository(full_path_before, path_before)
execute_rename_repository_hooks!(full_path_before)
@@ -2093,6 +2098,11 @@ class Project < ActiveRecord::Base
Gitlab::PagesTransfer.new.rename_project(path_before, self.path, namespace.full_path)
end
+ def untrack_site_statistics
+ SiteStatistic.untrack(STATISTICS_ATTRIBUTE)
+ self.project_feature.untrack_statistics_for_deletion!
+ end
+
def execute_rename_repository_hooks!(full_path_before)
# When we import a project overwriting the original project, there
# is a move operation. In that case we don't want to send the instructions.
diff --git a/app/models/protected_tag.rb b/app/models/protected_tag.rb
index a36f0d36262..94746141945 100644
--- a/app/models/protected_tag.rb
+++ b/app/models/protected_tag.rb
@@ -4,6 +4,8 @@ class ProtectedTag < ActiveRecord::Base
include Gitlab::ShellAdapter
include ProtectedRef
+ validates :name, uniqueness: { scope: :project_id }
+
protected_ref_access_levels :create
def self.protected?(project, ref_name)
diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb
index 833faf3bc82..c1f53b5da4f 100644
--- a/app/models/remote_mirror.rb
+++ b/app/models/remote_mirror.rb
@@ -150,6 +150,15 @@ class RemoteMirror < ActiveRecord::Base
result.to_s
end
+ def ensure_remote!
+ return unless project
+ return unless remote_name && url
+
+ # If this fails or the remote already exists, we won't know due to
+ # https://gitlab.com/gitlab-org/gitaly/issues/1317
+ project.repository.add_remote(remote_name, url)
+ end
+
private
def raw
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 69f375dc6f3..cf255c8951f 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -247,15 +247,22 @@ class Repository
# Git GC will delete commits from the repository that are no longer in any
# branches or tags, but we want to keep some of these commits around, for
# example if they have comments or CI builds.
- def keep_around(sha)
- return unless sha.present? && commit_by(oid: sha)
+ #
+ # For Geo's sake, pass in multiple shas rather than calling it multiple times,
+ # to avoid unnecessary syncing.
+ def keep_around(*shas)
+ shas.each do |sha|
+ begin
+ next unless sha.present? && commit_by(oid: sha)
- return if kept_around?(sha)
+ next if kept_around?(sha)
- # This will still fail if the file is corrupted (e.g. 0 bytes)
- raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false)
- rescue Gitlab::Git::CommandError => ex
- Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
+ # This will still fail if the file is corrupted (e.g. 0 bytes)
+ raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false)
+ rescue Gitlab::Git::CommandError => ex
+ Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
+ end
+ end
end
def kept_around?(sha)
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index a8d7a05f509..73c93b22c95 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -53,7 +53,7 @@ class GroupPolicy < BasePolicy
rule { has_access }.enable :read_namespace
- rule { developer }.enable :admin_milestones
+ rule { developer }.enable :admin_milestone
rule { reporter }.policy do
enable :admin_label
@@ -72,6 +72,8 @@ class GroupPolicy < BasePolicy
enable :admin_namespace
enable :admin_group_member
enable :change_visibility_level
+
+ enable :set_note_created_at
end
rule { can?(:read_nested_project_resources) }.policy do
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 00c58f15013..fd6cc504a3b 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -143,6 +143,10 @@ class ProjectPolicy < BasePolicy
enable :destroy_merge_request
enable :destroy_issue
enable :remove_pages
+
+ enable :set_issue_iid
+ enable :set_issue_created_at
+ enable :set_note_created_at
end
rule { can?(:guest_access) }.policy do
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 156b4b3c6ec..26e90e8cf8c 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -158,7 +158,7 @@ class GitPushService < BaseService
end
def process_default_branch
- offset = [push_commits_count - PROCESS_COMMIT_LIMIT, 0].max
+ offset = [push_commits_count_for_ref - PROCESS_COMMIT_LIMIT, 0].max
@push_commits = project.repository.commits(params[:newrev], offset: offset, limit: PROCESS_COMMIT_LIMIT)
project.after_create_default_branch
@@ -172,7 +172,7 @@ class GitPushService < BaseService
params[:newrev],
params[:ref],
@push_commits,
- commits_count: push_commits_count)
+ commits_count: commits_count)
end
def push_to_existing_branch?
@@ -213,8 +213,14 @@ class GitPushService < BaseService
end
end
- def push_commits_count
- strong_memoize(:push_commits_count) do
+ def commits_count
+ return push_commits_count_for_ref if default_branch? && push_to_new_branch?
+
+ Array(@push_commits).size
+ end
+
+ def push_commits_count_for_ref
+ strong_memoize(:push_commits_count_for_ref) do
project.repository.commit_count_for_ref(params[:ref])
end
end
diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb
index 12aeba4af71..93d84bd8a9c 100644
--- a/app/services/groups/destroy_service.rb
+++ b/app/services/groups/destroy_service.rb
@@ -12,12 +12,15 @@ module Groups
def execute
group.prepare_for_destroy
- group.projects.each do |project|
+ group.projects.includes(:project_feature).each do |project|
# Execute the destruction of the models immediately to ensure atomic cleanup.
success = ::Projects::DestroyService.new(project, current_user).execute
raise DestroyError, "Project #{project.id} can't be deleted" unless success
end
+ # reload the relation to prevent triggering destroy hooks on the projects again
+ group.projects.reload
+
group.children.each do |group|
# This needs to be synchronous since the namespace gets destroyed below
DestroyService.new(group, current_user).execute
diff --git a/app/services/issues/fetch_referenced_merge_requests_service.rb b/app/services/issues/fetch_referenced_merge_requests_service.rb
deleted file mode 100644
index 5e84f3c81c9..00000000000
--- a/app/services/issues/fetch_referenced_merge_requests_service.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module Issues
- class FetchReferencedMergeRequestsService < Issues::BaseService
- def execute(issue)
- referenced_merge_requests = issue.referenced_merge_requests(current_user)
- referenced_merge_requests = Gitlab::IssuableSorter.sort(project, referenced_merge_requests) { |i| i.iid.to_s }
- closed_by_merge_requests = issue.closed_by_merge_requests(current_user)
- closed_by_merge_requests = Gitlab::IssuableSorter.sort(project, closed_by_merge_requests) { |i| i.iid.to_s }
-
- [referenced_merge_requests, closed_by_merge_requests]
- end
- end
-end
diff --git a/app/services/issues/referenced_merge_requests_service.rb b/app/services/issues/referenced_merge_requests_service.rb
new file mode 100644
index 00000000000..40d78502697
--- /dev/null
+++ b/app/services/issues/referenced_merge_requests_service.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Issues
+ class ReferencedMergeRequestsService < Issues::BaseService
+ def execute(issue)
+ referenced = referenced_merge_requests(issue)
+ closed_by = closed_by_merge_requests(issue)
+ preloader = ActiveRecord::Associations::Preloader.new
+
+ preloader.preload(referenced + closed_by,
+ head_pipeline: { project: [:route, { namespace: :route }] })
+
+ [sort_by_iid(referenced), sort_by_iid(closed_by)]
+ end
+
+ def referenced_merge_requests(issue)
+ merge_requests = extract_merge_requests(issue)
+
+ cross_project_filter = -> (merge_requests) do
+ merge_requests.select { |mr| mr.target_project == project }
+ end
+
+ Ability.merge_requests_readable_by_user(
+ merge_requests,
+ current_user,
+ filters: {
+ read_cross_project: cross_project_filter
+ }
+ )
+ end
+
+ def closed_by_merge_requests(issue)
+ return [] unless issue.open?
+
+ merge_requests = extract_merge_requests(issue, filter: :system).select(&:open?)
+
+ return [] if merge_requests.empty?
+
+ ids = MergeRequestsClosingIssues.where(merge_request_id: merge_requests.map(&:id), issue_id: issue.id).pluck(:merge_request_id)
+ merge_requests.select { |mr| mr.id.in?(ids) }
+ end
+
+ private
+
+ def extract_merge_requests(issue, filter: nil)
+ ext = issue.all_references(current_user)
+ notes = issue_notes(issue)
+ notes = notes.select(&filter) if filter
+
+ notes.each do |note|
+ note.all_references(current_user, extractor: ext)
+ end
+
+ ext.merge_requests
+ end
+
+ def issue_notes(issue)
+ @issue_notes ||= {}
+ @issue_notes[issue] ||= issue.notes.includes(:author)
+ end
+
+ def sort_by_iid(merge_requests)
+ Gitlab::IssuableSorter.sort(project, merge_requests) { |mr| mr.iid.to_s }
+ end
+ end
+end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index bc988eb2a26..55750269bb4 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -128,8 +128,7 @@ module MergeRequests
#
def assign_title_and_description
assign_title_and_description_from_single_commit
- assign_title_from_issue if target_project.issues_enabled? || target_project.external_issue_tracker
-
+ merge_request.title ||= title_from_issue if target_project.issues_enabled? || target_project.external_issue_tracker
merge_request.title ||= source_branch.titleize.humanize
merge_request.title = wip_title if compare_commits.empty?
@@ -159,20 +158,18 @@ module MergeRequests
merge_request.description ||= commit.description.try(:strip)
end
- def assign_title_from_issue
+ def title_from_issue
return unless issue
- merge_request.title = "Resolve \"#{issue.title}\"" if issue.is_a?(Issue)
+ return "Resolve \"#{issue.title}\"" if issue.is_a?(Issue)
- return if merge_request.title.present?
+ return if issue_iid.blank?
- if issue_iid.present?
- title_parts = ["Resolve #{issue.to_reference}"]
- branch_title = source_branch.downcase.remove(issue_iid.downcase).titleize.humanize
+ title_parts = ["Resolve #{issue.to_reference}"]
+ branch_title = source_branch.downcase.remove(issue_iid.downcase).titleize.humanize
- title_parts << "\"#{branch_title}\"" if branch_title.present?
- merge_request.title = title_parts.join(' ')
- end
+ title_parts << "\"#{branch_title}\"" if branch_title.present?
+ title_parts.join(' ')
end
def issue_iid
diff --git a/app/services/milestones/destroy_service.rb b/app/services/milestones/destroy_service.rb
index 15c04525075..7cda802c120 100644
--- a/app/services/milestones/destroy_service.rb
+++ b/app/services/milestones/destroy_service.rb
@@ -3,8 +3,6 @@
module Milestones
class DestroyService < Milestones::BaseService
def execute(milestone)
- return unless milestone.project_milestone?
-
Milestone.transaction do
update_params = { milestone: nil }
@@ -16,15 +14,21 @@ module Milestones
MergeRequests::UpdateService.new(parent, current_user, update_params).execute(merge_request)
end
- event_service.destroy_milestone(milestone, current_user)
-
- Event.for_milestone_id(milestone.id).each do |event|
- event.target_id = nil
- event.save
- end
+ log_destroy_event_for(milestone)
milestone.destroy
end
end
+
+ def log_destroy_event_for(milestone)
+ return if milestone.group_milestone?
+
+ event_service.destroy_milestone(milestone, current_user)
+
+ Event.for_milestone_id(milestone.id).each do |event|
+ event.target_id = nil
+ event.save
+ end
+ end
end
end
diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb
index 4651f7c4f8f..591b38b8151 100644
--- a/app/services/projects/update_remote_mirror_service.rb
+++ b/app/services/projects/update_remote_mirror_service.rb
@@ -10,6 +10,7 @@ module Projects
return success unless remote_mirror.enabled?
begin
+ remote_mirror.ensure_remote!
repository.fetch_remote(remote_mirror.remote_name, no_tags: true)
opts = {}
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 8838ed06324..a4c4c9e4812 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -402,7 +402,7 @@ module QuickActions
match[1] if match
end
command :award do |name|
- if name && issuable.user_can_award?(current_user, name)
+ if name && issuable.user_can_award?(current_user)
@updates[:emoji_award] = name
end
end
diff --git a/app/views/admin/hook_logs/show.html.haml b/app/views/admin/hook_logs/show.html.haml
index 2eb3ac85722..86729dbe7bc 100644
--- a/app/views/admin/hook_logs/show.html.haml
+++ b/app/views/admin/hook_logs/show.html.haml
@@ -4,7 +4,6 @@
%hr
-= link_to 'Resend Request', retry_admin_hook_hook_log_path(@hook, @hook_log), class: "btn btn-default float-right prepend-left-10"
+= link_to 'Resend Request', retry_admin_hook_hook_log_path(@hook, @hook_log), method: :post, class: "btn btn-default float-right prepend-left-10"
= render partial: 'shared/hook_logs/content', locals: { hook_log: @hook_log }
-
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 029efadd75d..a74e052707f 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -39,6 +39,10 @@
%strong= email.email
= link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-sm btn btn-remove float-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
%i.fa.fa-times
+ %li
+ %span.light ID:
+ %strong
+ = @user.id
%li.two-factor-status
%span.light Two-factor Authentication:
diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml
index 8ca9fb4512e..30d7b21b1b8 100644
--- a/app/views/award_emoji/_awards_block.html.haml
+++ b/app/views/award_emoji/_awards_block.html.haml
@@ -3,7 +3,7 @@
.awards.js-awards-block{ class: ("hidden" if !inline && grouped_emojis.empty?), data: { award_url: toggle_award_url(awardable) } }
- awards_sort(grouped_emojis).each do |emoji, awards|
%button.btn.award-control.js-emoji-btn.has-tooltip{ type: "button",
- class: [(award_state_class(awardable, awards, current_user)), (award_user_authored_class(emoji) if user_authored)],
+ class: [(award_state_class(awardable, awards, current_user))],
data: { placement: "bottom", title: award_user_list(awards, current_user) } }
= emoji_icon(emoji)
%span.award-control-text.js-counter
@@ -13,7 +13,6 @@
.award-menu-holder.js-award-holder
%button.btn.award-control.has-tooltip.js-add-award{ type: 'button',
'aria-label': _('Add reaction'),
- class: ("js-user-authored" if user_authored),
data: { title: _('Add reaction'), placement: "bottom" } }
%span{ class: "award-control-icon award-control-icon-neutral" }= custom_icon('emoji_slightly_smiling_face')
%span{ class: "award-control-icon award-control-icon-positive" }= custom_icon('emoji_smiley')
diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml
index 13f96b9747c..c26eb873718 100644
--- a/app/views/ci/runner/_how_to_setup_runner.html.haml
+++ b/app/views/ci/runner/_how_to_setup_runner.html.haml
@@ -1,6 +1,6 @@
- link = link_to _("Install GitLab Runner"), 'https://docs.gitlab.com/runner/install/', target: '_blank'
.append-bottom-10
- %h4= _("Setup a #{type} Runner manually")
+ %h4= _("Setup a %{type} Runner manually") % { type: type }
%ol
%li
diff --git a/app/views/ci/status/_dropdown_graph_badge.html.haml b/app/views/ci/status/_dropdown_graph_badge.html.haml
index 8b0463db000..9de9143e8b1 100644
--- a/app/views/ci/status/_dropdown_graph_badge.html.haml
+++ b/app/views/ci/status/_dropdown_graph_badge.html.haml
@@ -6,12 +6,12 @@
- tooltip = "#{subject.name} - #{status.status_tooltip}"
- if status.has_details?
- = link_to status.details_path, class: 'mini-pipeline-graph-dropdown-item', data: { toggle: 'tooltip', title: tooltip, html: 'true', container: 'body' } do
+ = link_to status.details_path, class: 'mini-pipeline-graph-dropdown-item', data: { toggle: 'tooltip', title: tooltip, container: 'body' } do
%span{ class: klass }= sprite_icon(status.icon)
%span.ci-build-text= subject.name
- else
- .menu-item.mini-pipeline-graph-dropdown-item{ data: { toggle: 'tooltip', html: 'true', title: tooltip, container: 'body' } }
+ .menu-item.mini-pipeline-graph-dropdown-item{ data: { toggle: 'tooltip', title: tooltip, container: 'body' } }
%span{ class: klass }= sprite_icon(status.icon)
%span.ci-build-text= subject.name
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index f5f621507b8..b6424df55cd 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -5,7 +5,7 @@
.nav-controls
= render 'shared/milestones_sort_dropdown'
- - if can?(current_user, :admin_milestones, @group)
+ - if can?(current_user, :admin_milestone, @group)
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
.milestones
diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml
index f0d1e837317..f4a29ed18dc 100644
--- a/app/views/import/_githubish_status.html.haml
+++ b/app/views/import/_githubish_status.html.haml
@@ -45,7 +45,7 @@
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend
.input-group-text /
- = text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
+ = text_field_tag :path, sanitize_project_name(repo.name), class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do
= has_ci_cd_only_params? ? _('Connect') : _('Import')
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index a75b7aa9dd2..3b1b5e55302 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -63,7 +63,7 @@
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend
.input-group-text /
- = text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
+ = text_field_tag :path, sanitize_project_name(repo.slug), class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: 'btn btn-import js-add-to-import' do
= _('Import')
diff --git a/app/views/import/bitbucket_server/status.html.haml b/app/views/import/bitbucket_server/status.html.haml
index 3d05a5e696f..ae09e0dfa18 100644
--- a/app/views/import/bitbucket_server/status.html.haml
+++ b/app/views/import/bitbucket_server/status.html.haml
@@ -61,7 +61,7 @@
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend
.input-group-text /
- = text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
+ = text_field_tag :path, sanitize_project_name(repo.slug), class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: 'btn btn-import js-add-to-import' do
Import
diff --git a/app/views/projects/_issuable_by_email.html.haml b/app/views/projects/_issuable_by_email.html.haml
index 22adf5b4008..d59191a6f87 100644
--- a/app/views/projects/_issuable_by_email.html.haml
+++ b/app/views/projects/_issuable_by_email.html.haml
@@ -19,9 +19,16 @@
= text_field_tag :issuable_email, email, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
= clipboard_button(target: '#issuable_email', class: 'btn btn-clipboard input-group-text btn-transparent d-none d-sm-block')
+
+ - if issuable_type == 'issue'
+ - enter_title_text = _('Enter the issue title')
+ - enter_description_text = _('Enter the issue description')
+ - else
+ - enter_title_text = _('Enter the merge request title')
+ - enter_description_text = _('Enter the merge request description')
= mail_to email, class: 'btn btn-clipboard btn-transparent',
- subject: _("Enter the #{name} title"),
- body: _("Enter the #{name} description"),
+ subject: enter_title_text,
+ body: enter_description_text,
title: _('Send email'),
data: { toggle: 'tooltip', placement: 'bottom' } do
= sprite_icon('mail')
diff --git a/app/views/projects/commits/_commit_list.html.haml b/app/views/projects/commits/_commit_list.html.haml
index 8f8eb2c3d5a..6ed65d07202 100644
--- a/app/views/projects/commits/_commit_list.html.haml
+++ b/app/views/projects/commits/_commit_list.html.haml
@@ -1,9 +1,10 @@
-- commits, hidden = limited_commits(@commits)
+- commits = @commits
+- hidden = @hidden_commit_count
- commits = Commit.decorate(commits, @project)
.card
.card-header
- Commits (#{@commits.count})
+ Commits (#{@total_commit_count})
- if hidden > 0
%ul.content-list
- commits.each do |commit|
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index ac6852751be..ec05ff50f25 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -2,7 +2,8 @@
- project = local_assigns.fetch(:project) { merge_request&.project }
- ref = local_assigns.fetch(:ref) { merge_request&.source_branch }
-- commits, hidden = limited_commits(@commits)
+- commits = @commits
+- hidden = @hidden_commit_count
- commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits|
%li.commit-header.js-commit-header{ data: { day: day } }
diff --git a/app/views/projects/diffs/_line.html.haml b/app/views/projects/diffs/_line.html.haml
index cd0fb21f8a7..ffdca500abe 100644
--- a/app/views/projects/diffs/_line.html.haml
+++ b/app/views/projects/diffs/_line.html.haml
@@ -32,9 +32,9 @@
%a{ href: "##{line_code}", data: { linenumber: link_text } }
%td.line_content.noteable_line{ class: type }<
- if email
- %pre= line.text
+ %pre= line.rich_text
- else
- = diff_line_content(line.text)
+ = diff_line_content(line.rich_text)
- if line_discussions&.any?
- discussion_expanded = local_assigns.fetch(:discussion_expanded, line_discussions.any?(&:expanded?))
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index 1f0ca211074..e47361354f3 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -24,7 +24,7 @@
- discussion_left = discussions_left.try(:first)
- if discussion_left && discussion_left.resolvable?
%diff-note-avatars{ "discussion-id" => discussion_left.id }
- %td.line_content.parallel.noteable_line.left-side{ id: left_line_code, class: left.type }= diff_line_content(left.text)
+ %td.line_content.parallel.noteable_line.left-side{ id: left_line_code, class: left.type }= diff_line_content(left.rich_text)
- else
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel.left-side
@@ -45,7 +45,7 @@
- discussion_right = discussions_right.try(:first)
- if discussion_right && discussion_right.resolvable?
%diff-note-avatars{ "discussion-id" => discussion_right.id }
- %td.line_content.parallel.noteable_line.right-side{ id: right_line_code, class: right.type }= diff_line_content(right.text)
+ %td.line_content.parallel.noteable_line.right-side{ id: right_line_code, class: right.type }= diff_line_content(right.rich_text)
- else
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel.right-side
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 30544dde451..e37a444c1c9 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -78,7 +78,7 @@
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "sharing-permissions-form" }, authenticity_token: true do |f|
%input{ name: 'update_section', type: 'hidden', value: 'js-shared-permissions' }
-# haml-lint:disable InlineJavaScript
- %script.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data(@project)
+ %script.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data_json(@project)
.js-project-permissions-form
= f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/projects/hook_logs/show.html.haml b/app/views/projects/hook_logs/show.html.haml
index e51efa85df0..bd8ca5e7d70 100644
--- a/app/views/projects/hook_logs/show.html.haml
+++ b/app/views/projects/hook_logs/show.html.haml
@@ -4,6 +4,6 @@
Request details
.col-lg-9
- = link_to 'Resend Request', retry_project_hook_hook_log_path(@project, @hook, @hook_log), class: "btn btn-default float-right prepend-left-10"
+ = link_to 'Resend Request', retry_project_hook_hook_log_path(@project, @hook, @hook_log), method: :post, class: "btn btn-default float-right prepend-left-10"
= render partial: 'shared/hook_logs/content', locals: { hook_log: @hook_log }
diff --git a/app/views/projects/jobs/_sidebar.html.haml b/app/views/projects/jobs/_sidebar.html.haml
index 86b2b8bf2f7..acc1e17b811 100644
--- a/app/views/projects/jobs/_sidebar.html.haml
+++ b/app/views/projects/jobs/_sidebar.html.haml
@@ -82,7 +82,7 @@
- builds.select{|build| build.status == build_status}.each do |build|
.build-job{ class: sidebar_build_class(build, @build), data: { stage: build.stage } }
- tooltip = sanitize(build.tooltip_message.dup)
- = link_to(project_job_path(@project, build), data: { toggle: 'tooltip', html: 'true', title: tooltip, container: 'body' }) do
+ = link_to(project_job_path(@project, build), data: { toggle: 'tooltip', title: tooltip, container: 'body' }) do
= sprite_icon('arrow-right', size:16, css_class: 'icon-arrow-right')
%span{ class: "ci-status-icon-#{build.status}" }
= ci_icon_for_status(build.status)
diff --git a/app/views/projects/merge_requests/_how_to_merge.html.haml b/app/views/projects/merge_requests/_how_to_merge.html.haml
index 62dd21ef6e0..d3871453b9f 100644
--- a/app/views/projects/merge_requests/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/_how_to_merge.html.haml
@@ -1,5 +1,5 @@
#modal_merge_info.modal{ tabindex: '-1' }
- .modal-dialog
+ .modal-dialog.modal-lg
.modal-content
.modal-header
%h3.modal-title Check out, review, and merge locally
diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml
index f7a5d85500f..d5c4134dee2 100644
--- a/app/views/projects/merge_requests/creations/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml
@@ -33,7 +33,7 @@
%li.commits-tab.new-tab
= link_to url_for(safe_params), data: {target: 'div#commits', action: 'new', toggle: 'tabvue'} do
Commits
- %span.badge.badge-pill= @commits.size
+ %span.badge.badge-pill= @total_commit_count
- if @pipelines.any?
%li.builds-tab
= link_to url_for(safe_params.merge(action: 'pipelines')), data: {target: 'div#pipelines', action: 'pipelines', toggle: 'tabvue'} do
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 2a9e20c2caa..0a684f9016a 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -43,18 +43,7 @@
- else
= link_to 'Reopen milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-nr btn-grouped"
- %button.js-delete-milestone-button.btn.btn-grouped.btn-danger{ data: { toggle: 'modal',
- target: '#delete-milestone-modal',
- milestone_id: @milestone.id,
- milestone_title: markdown_field(@milestone, :title),
- milestone_url: project_milestone_path(@project, @milestone),
- milestone_issue_count: @milestone.issues.count,
- milestone_merge_request_count: @milestone.merge_requests.count },
- disabled: true }
- = _('Delete')
- = icon('spin spinner', class: 'js-loading-icon hidden' )
-
- #delete-milestone-modal
+ = render 'shared/milestones/delete_button'
%a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: "#" }
= icon('angle-double-left')
diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml
index e051f9e6331..35a6885318a 100644
--- a/app/views/projects/mirrors/_instructions.html.haml
+++ b/app/views/projects/mirrors/_instructions.html.haml
@@ -4,7 +4,9 @@
= _('The repository must be accessible over <code>http://</code>,
<code>https://</code>, <code>ssh://</code> and <code>git://</code>.').html_safe
%li= _('Include the username in the URL if required: <code>https://username@gitlab.company.com/group/project.git</code>.').html_safe
- %li= _("The update action will time out after #{import_will_timeout_message(Gitlab.config.gitlab_shell.git_timeout)} minutes. For big repositories, use a clone/push combination.")
+ %li
+ - minutes = Gitlab.config.gitlab_shell.git_timeout / 60
+ = _("The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination.") % { number_of_minutes: minutes }
%li= _('The Git LFS objects will <strong>not</strong> be synced.').html_safe
%li
= _('This user will be the author of all events in the activity feed that are the result of an update,
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index b4fe1cabdfd..e9008d60098 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -40,7 +40,7 @@
- if note.emoji_awardable?
- user_authored = note.user_authored?(current_user)
.note-actions-item
- = button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji #{'js-user-authored' if user_authored} has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
+ = button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji} has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
= icon('spinner spin')
%span{ class: 'link-highlight award-control-icon-neutral' }= custom_icon('emoji_slightly_smiling_face')
%span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')
diff --git a/app/views/shared/milestones/_delete_button.html.haml b/app/views/shared/milestones/_delete_button.html.haml
new file mode 100644
index 00000000000..e236c24b088
--- /dev/null
+++ b/app/views/shared/milestones/_delete_button.html.haml
@@ -0,0 +1,14 @@
+- milestone_url = @milestone.project_milestone? ? project_milestone_path(@project, @milestone) : group_milestone_path(@group, @milestone)
+
+%button.js-delete-milestone-button.btn.btn-grouped.btn-danger{ data: { toggle: 'modal',
+ target: '#delete-milestone-modal',
+ milestone_id: @milestone.id,
+ milestone_title: markdown_field(@milestone, :title),
+ milestone_url: milestone_url,
+ milestone_issue_count: @milestone.issues.count,
+ milestone_merge_request_count: @milestone.merge_requests.count },
+ disabled: true }
+ = _('Delete')
+ = icon('spin spinner', class: 'js-loading-icon hidden' )
+
+#delete-milestone-modal
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index c559945a9c9..3dd2842be4f 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -16,6 +16,9 @@
= milestone_date_range(milestone)
%div
= render('shared/milestone_expired', milestone: milestone)
+ - if milestone.group_milestone?
+ .label-badge.label-badge-blue.d-inline-block
+ = milestone.group.full_name
- if milestone.legacy_group_milestone?
.projects
- milestone.milestones.each do |milestone|
@@ -49,7 +52,7 @@
- unless milestone.active?
= link_to 'Reopen Milestone', project_milestone_path(@project, milestone, {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
- if @group
- - if can?(current_user, :admin_milestones, @group)
+ - if can?(current_user, :admin_milestone, @group)
- if milestone.closed?
= link_to 'Reopen Milestone', group_milestone_route(milestone, {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
- else
diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml
index 320e3788a0f..0499b04a482 100644
--- a/app/views/shared/milestones/_top.html.haml
+++ b/app/views/shared/milestones/_top.html.haml
@@ -23,7 +23,7 @@
= milestone_date_range(milestone)
- if group
.float-right
- - if can?(current_user, :admin_milestones, group)
+ - if can?(current_user, :admin_milestone, group)
- if milestone.group_milestone?
= link_to edit_group_milestone_path(group, milestone), class: "btn btn btn-grouped" do
Edit
@@ -32,6 +32,9 @@
- else
= link_to 'Reopen Milestone', group_milestone_route(milestone, {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
+ - unless is_dynamic_milestone
+ = render 'shared/milestones/delete_button'
+
= render 'shared/milestones/deprecation_message' if is_dynamic_milestone
.detail-page-description.milestone-detail
diff --git a/app/views/snippets/notes/_actions.html.haml b/app/views/snippets/notes/_actions.html.haml
index 3a50324770d..e1f7ee80ebb 100644
--- a/app/views/snippets/notes/_actions.html.haml
+++ b/app/views/snippets/notes/_actions.html.haml
@@ -2,7 +2,7 @@
- if note.emoji_awardable?
- user_authored = note.user_authored?(current_user)
.note-actions-item
- = link_to '#', title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji #{'js-user-authored' if user_authored} has-tooltip", data: { position: 'right' } do
+ = link_to '#', title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip", data: { position: 'right' } do
= icon('spinner spin')
%span{ class: 'link-highlight award-control-icon-neutral' }= custom_icon('emoji_slightly_smiling_face')
%span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')
diff --git a/changelogs/unreleased/43096-controller-projects-issuescontroller-referenced_merge_requests-json-executes-more-than-100-sql-queries.yml b/changelogs/unreleased/43096-controller-projects-issuescontroller-referenced_merge_requests-json-executes-more-than-100-sql-queries.yml
new file mode 100644
index 00000000000..f4744c868ef
--- /dev/null
+++ b/changelogs/unreleased/43096-controller-projects-issuescontroller-referenced_merge_requests-json-executes-more-than-100-sql-queries.yml
@@ -0,0 +1,5 @@
+---
+title: Improve performance when fetching related merge requests for an issue
+merge_request: 21237
+author:
+type: performance
diff --git a/changelogs/unreleased/43625-increase-modal-checkout.yml b/changelogs/unreleased/43625-increase-modal-checkout.yml
new file mode 100644
index 00000000000..877550924c1
--- /dev/null
+++ b/changelogs/unreleased/43625-increase-modal-checkout.yml
@@ -0,0 +1,5 @@
+---
+title: Increase width of checkout branch modal box
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/49110-update-mr-widget-styles.yml b/changelogs/unreleased/49110-update-mr-widget-styles.yml
new file mode 100644
index 00000000000..e54866a0908
--- /dev/null
+++ b/changelogs/unreleased/49110-update-mr-widget-styles.yml
@@ -0,0 +1,5 @@
+---
+title: Truncate branch names and update "commits behind" text in MR page
+merge_request: 21206
+author:
+type: changed
diff --git a/changelogs/unreleased/49292-add-group-name-badge-under-milestone.yml b/changelogs/unreleased/49292-add-group-name-badge-under-milestone.yml
new file mode 100644
index 00000000000..69089cfe357
--- /dev/null
+++ b/changelogs/unreleased/49292-add-group-name-badge-under-milestone.yml
@@ -0,0 +1,5 @@
+---
+title: Add group name badge under group milestone
+merge_request: 21384
+author:
+type: added
diff --git a/changelogs/unreleased/50101-env-block.yml b/changelogs/unreleased/50101-env-block.yml
new file mode 100644
index 00000000000..11e603e7a79
--- /dev/null
+++ b/changelogs/unreleased/50101-env-block.yml
@@ -0,0 +1,5 @@
+---
+title: Creates vue component for environments information in job log view
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/50345-hashed-storage-feature-flag.yml b/changelogs/unreleased/50345-hashed-storage-feature-flag.yml
new file mode 100644
index 00000000000..4c5182b843b
--- /dev/null
+++ b/changelogs/unreleased/50345-hashed-storage-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Feature flag to disable Hashed Storage migration when renaming a repository
+merge_request: 21291
+author:
+type: added
diff --git a/changelogs/unreleased/50441-high-number-of-statement-timeouts-in-groupdestroyworker-due-to-sitestatistics.yml b/changelogs/unreleased/50441-high-number-of-statement-timeouts-in-groupdestroyworker-due-to-sitestatistics.yml
new file mode 100644
index 00000000000..3e360f8d6bb
--- /dev/null
+++ b/changelogs/unreleased/50441-high-number-of-statement-timeouts-in-groupdestroyworker-due-to-sitestatistics.yml
@@ -0,0 +1,5 @@
+---
+title: Removing a group no longer triggers hooks for project deletion twice
+merge_request: 21366
+author:
+type: fixed
diff --git a/changelogs/unreleased/50584-fix-ide-commit-twice.yml b/changelogs/unreleased/50584-fix-ide-commit-twice.yml
new file mode 100644
index 00000000000..92b292cf4ab
--- /dev/null
+++ b/changelogs/unreleased/50584-fix-ide-commit-twice.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Web IDE unable to commit to same file twice
+merge_request: 21372
+author:
+type: fixed
diff --git a/changelogs/unreleased/50801-error-getting-performance-bar-results-for-uuid.yml b/changelogs/unreleased/50801-error-getting-performance-bar-results-for-uuid.yml
new file mode 100644
index 00000000000..6e57a215367
--- /dev/null
+++ b/changelogs/unreleased/50801-error-getting-performance-bar-results-for-uuid.yml
@@ -0,0 +1,5 @@
+---
+title: Don't show flash messages for performance bar errors
+merge_request: 21411
+author:
+type: other
diff --git a/changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml b/changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml
new file mode 100644
index 00000000000..94098dd0144
--- /dev/null
+++ b/changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml
@@ -0,0 +1,6 @@
+---
+title: Show '< 1%' when percent value evaluated is less than 1 on Stacked Progress
+ Bar
+merge_request: 21306
+author:
+type: fixed
diff --git a/changelogs/unreleased/api-protected-tags.yml b/changelogs/unreleased/api-protected-tags.yml
new file mode 100644
index 00000000000..6e7ecf24b6e
--- /dev/null
+++ b/changelogs/unreleased/api-protected-tags.yml
@@ -0,0 +1,5 @@
+---
+title: 'API: Protected tags'
+merge_request: 14986
+author: Robert Schilling
+type: added
diff --git a/changelogs/unreleased/bvl-add-galician.yml b/changelogs/unreleased/bvl-add-galician.yml
new file mode 100644
index 00000000000..e7035901ace
--- /dev/null
+++ b/changelogs/unreleased/bvl-add-galician.yml
@@ -0,0 +1,5 @@
+---
+title: Add Galician as an available language.
+merge_request: 21202
+author:
+type: added
diff --git a/changelogs/unreleased/ccr-43283_allow_author_upvote.yml b/changelogs/unreleased/ccr-43283_allow_author_upvote.yml
new file mode 100644
index 00000000000..12ef6e3f790
--- /dev/null
+++ b/changelogs/unreleased/ccr-43283_allow_author_upvote.yml
@@ -0,0 +1,5 @@
+---
+title: Allow author to vote on their own issue and MRs
+merge_request: 21203
+author:
+type: changed
diff --git a/changelogs/unreleased/ccr-48800-ping_for_boards.yml b/changelogs/unreleased/ccr-48800-ping_for_boards.yml
new file mode 100644
index 00000000000..c08578cddba
--- /dev/null
+++ b/changelogs/unreleased/ccr-48800-ping_for_boards.yml
@@ -0,0 +1,6 @@
+---
+title: Adds count for different board list types (label lists, assignee lists, and
+ milestone lists) to usage statistics.
+merge_request: 21208
+author:
+type: changed
diff --git a/changelogs/unreleased/expose-users-id-in-admin-users-show-page.yml b/changelogs/unreleased/expose-users-id-in-admin-users-show-page.yml
new file mode 100644
index 00000000000..0b8ae527214
--- /dev/null
+++ b/changelogs/unreleased/expose-users-id-in-admin-users-show-page.yml
@@ -0,0 +1,5 @@
+---
+title: Expose user's id in /admin/users/ show page
+merge_request:
+author: Eva Kadlecova
+type: changed
diff --git a/changelogs/unreleased/fix-api-group-createdat.yml b/changelogs/unreleased/fix-api-group-createdat.yml
new file mode 100644
index 00000000000..e628facf1bf
--- /dev/null
+++ b/changelogs/unreleased/fix-api-group-createdat.yml
@@ -0,0 +1,5 @@
+---
+title: Allow date parameters on Issues, Notes, and Discussions API for group owners
+merge_request: 21342
+author: Florent Dubois
+type: fixed
diff --git a/changelogs/unreleased/fix-mr-title-fallback-logic.yml b/changelogs/unreleased/fix-mr-title-fallback-logic.yml
new file mode 100644
index 00000000000..5056c38573b
--- /dev/null
+++ b/changelogs/unreleased/fix-mr-title-fallback-logic.yml
@@ -0,0 +1,5 @@
+---
+title: Fix fallback logic for automatic MR title assignment
+merge_request: 20930
+author: Franz Liedke
+type: fixed
diff --git a/changelogs/unreleased/fix_emojis_cutting_and_regressions.yml b/changelogs/unreleased/fix_emojis_cutting_and_regressions.yml
new file mode 100644
index 00000000000..a9c1b88a61c
--- /dev/null
+++ b/changelogs/unreleased/fix_emojis_cutting_and_regressions.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Emojis cutting in the right way
+merge_request:
+author: Alexander Popov
+type: fixed
diff --git a/changelogs/unreleased/issue_36138.yml b/changelogs/unreleased/issue_36138.yml
new file mode 100644
index 00000000000..2fb2eea65f5
--- /dev/null
+++ b/changelogs/unreleased/issue_36138.yml
@@ -0,0 +1,5 @@
+---
+title: Allow to delete group milestones
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/jprovazn-fix-form-uploads.yml b/changelogs/unreleased/jprovazn-fix-form-uploads.yml
new file mode 100644
index 00000000000..8bcee335e93
--- /dev/null
+++ b/changelogs/unreleased/jprovazn-fix-form-uploads.yml
@@ -0,0 +1,5 @@
+---
+title: Accept upload files in public/uplaods/tmp when using accelerated uploads.
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/rails5-fix-import-merge-request-creator.yml b/changelogs/unreleased/rails5-fix-import-merge-request-creator.yml
new file mode 100644
index 00000000000..661bd748333
--- /dev/null
+++ b/changelogs/unreleased/rails5-fix-import-merge-request-creator.yml
@@ -0,0 +1,5 @@
+---
+title: 'Rails5: fix can''t quote ActiveSupport::HashWithIndifferentAccess'
+merge_request: 21397
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/rails5-silence-stream.yml b/changelogs/unreleased/rails5-silence-stream.yml
new file mode 100644
index 00000000000..df4fd14a077
--- /dev/null
+++ b/changelogs/unreleased/rails5-silence-stream.yml
@@ -0,0 +1,5 @@
+---
+title: 'Rails 5: replace removed silence_stream'
+merge_request: 21387
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/rails5-update-gemfile-lock.yml b/changelogs/unreleased/rails5-update-gemfile-lock.yml
new file mode 100644
index 00000000000..3891b16e2b8
--- /dev/null
+++ b/changelogs/unreleased/rails5-update-gemfile-lock.yml
@@ -0,0 +1,5 @@
+---
+title: Rails5 update Gemfile.rails5.lock
+merge_request: 21388
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/security-49085-persistent-xss-rendering.yml b/changelogs/unreleased/security-49085-persistent-xss-rendering.yml
new file mode 100644
index 00000000000..dc15d356c1c
--- /dev/null
+++ b/changelogs/unreleased/security-49085-persistent-xss-rendering.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed persistent XSS rendering/escaping of diff location lines
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/sh-block-link-local-master.yml b/changelogs/unreleased/sh-block-link-local-master.yml
new file mode 100644
index 00000000000..0a6017479af
--- /dev/null
+++ b/changelogs/unreleased/sh-block-link-local-master.yml
@@ -0,0 +1,5 @@
+---
+title: Block link-local addresses in URLBlocker
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/sh-conditional-system-hook-push.yml b/changelogs/unreleased/sh-conditional-system-hook-push.yml
deleted file mode 100644
index 3a1a1b3d36c..00000000000
--- a/changelogs/unreleased/sh-conditional-system-hook-push.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Eliminate unnecessary and duplicate system hook fires
-merge_request: 21337
-author:
-type: performance
diff --git a/changelogs/unreleased/sh-fix-issue-50562.yml b/changelogs/unreleased/sh-fix-issue-50562.yml
new file mode 100644
index 00000000000..a207dd28622
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-50562.yml
@@ -0,0 +1,5 @@
+---
+title: Fix remote mirrors failing if Git remotes have not been added
+merge_request: 21351
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-insert-git-data-in-separate-transaction.yml b/changelogs/unreleased/sh-insert-git-data-in-separate-transaction.yml
new file mode 100644
index 00000000000..116929b2f53
--- /dev/null
+++ b/changelogs/unreleased/sh-insert-git-data-in-separate-transaction.yml
@@ -0,0 +1,5 @@
+---
+title: 'Bitbucket Server importer: Eliminate most idle-in-transaction issues'
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-limit-commit-renderering.yml b/changelogs/unreleased/sh-limit-commit-renderering.yml
new file mode 100644
index 00000000000..c44c67bcc90
--- /dev/null
+++ b/changelogs/unreleased/sh-limit-commit-renderering.yml
@@ -0,0 +1,5 @@
+---
+title: Speed up diff comparisons by limiting number of commit messages rendered
+merge_request: 21335
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-sanitize-project-import-names.yml b/changelogs/unreleased/sh-sanitize-project-import-names.yml
new file mode 100644
index 00000000000..6e0284bda08
--- /dev/null
+++ b/changelogs/unreleased/sh-sanitize-project-import-names.yml
@@ -0,0 +1,5 @@
+---
+title: Use slugs for default project path and sanitize names before import
+merge_request: 21367
+author:
+type: fixed
diff --git a/changelogs/unreleased/winh-default-status-emoji.yml b/changelogs/unreleased/winh-default-status-emoji.yml
new file mode 100644
index 00000000000..00cca4db0a6
--- /dev/null
+++ b/changelogs/unreleased/winh-default-status-emoji.yml
@@ -0,0 +1,5 @@
+---
+title: Display default status emoji if only message is entered
+merge_request: 21330
+author:
+type: changed
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 7ee960970f8..fa1f79a90be 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -59,7 +59,7 @@ namespace :admin do
resources :hook_logs, only: [:show] do
member do
- get :retry
+ post :retry
end
end
end
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 25fbb38ba87..d7313e43786 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -37,7 +37,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
post :toggle_subscription, on: :member
end
- resources :milestones, constraints: { id: %r{[^/]+} }, only: [:index, :show, :edit, :update, :new, :create] do
+ resources :milestones, constraints: { id: %r{[^/]+} } do
member do
get :merge_requests
get :participants
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 0220e88c819..34f49546983 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -307,7 +307,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resources :hook_logs, only: [:show] do
member do
- get :retry
+ post :retry
end
end
end
diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile
index a1f94dc6004..713ed95a04c 100644
--- a/danger/changelog/Dangerfile
+++ b/danger/changelog/Dangerfile
@@ -53,9 +53,11 @@ end
changelog_needed = (gitlab.mr_labels & NO_CHANGELOG_LABELS).empty?
changelog_found = git.added_files.find { |path| path =~ %r{\A(ee/)?(changelogs/unreleased)(-ee)?/} }
+mr_title = gitlab.mr_json["title"].gsub(/^WIP: */, '')
+
if git.modified_files.include?("CHANGELOG.md")
fail "**CHANGELOG.md was edited.** Please remove the additions and create a CHANGELOG entry.\n\n" +
- format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: gitlab.mr_json["title"], labels: presented_no_changelog_labels)
+ format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: mr_title, labels: presented_no_changelog_labels)
end
if changelog_needed
@@ -63,6 +65,6 @@ if changelog_needed
check_changelog(changelog_found)
else
warn "**[CHANGELOG missing](https://docs.gitlab.com/ce/development/changelog.html).**\n\n" +
- format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: gitlab.mr_json["title"], labels: presented_no_changelog_labels)
+ format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: mr_title, labels: presented_no_changelog_labels)
end
end
diff --git a/db/migrate/20180711103851_drop_duplicate_protected_tags.rb b/db/migrate/20180711103851_drop_duplicate_protected_tags.rb
new file mode 100644
index 00000000000..8fa2137551e
--- /dev/null
+++ b/db/migrate/20180711103851_drop_duplicate_protected_tags.rb
@@ -0,0 +1,45 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class DropDuplicateProtectedTags < ActiveRecord::Migration
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ BATCH_SIZE = 1000
+
+ class Project < ActiveRecord::Base
+ self.table_name = 'projects'
+
+ include ::EachBatch
+ end
+
+ class ProtectedTag < ActiveRecord::Base
+ self.table_name = 'protected_tags'
+ end
+
+ def up
+ Project.each_batch(of: BATCH_SIZE) do |projects|
+ ids = ProtectedTag
+ .where(project_id: projects)
+ .group(:name, :project_id)
+ .select('max(id)')
+
+ tags = ProtectedTag
+ .where(project_id: projects)
+ .where.not(id: ids)
+
+ if Gitlab::Database.postgresql?
+ tags.delete_all
+ else
+ # Workaround needed for MySQL
+ sql = "SELECT id FROM (#{tags.to_sql}) protected_tags"
+
+ ProtectedTag.where("id IN (#{sql})").delete_all # rubocop:disable GitlabSecurity/SqlInjection
+ end
+ end
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/20180711103922_add_protected_tags_index.rb b/db/migrate/20180711103922_add_protected_tags_index.rb
new file mode 100644
index 00000000000..7ed2258ebaf
--- /dev/null
+++ b/db/migrate/20180711103922_add_protected_tags_index.rb
@@ -0,0 +1,18 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddProtectedTagsIndex < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :protected_tags, [:project_id, :name], unique: true
+ end
+
+ def down
+ remove_concurrent_index :protected_tags, [:project_id, :name]
+ end
+end
diff --git a/db/migrate/20180815175440_add_index_on_list_type.rb b/db/migrate/20180815175440_add_index_on_list_type.rb
new file mode 100644
index 00000000000..aad805e436e
--- /dev/null
+++ b/db/migrate/20180815175440_add_index_on_list_type.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+class AddIndexOnListType < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :lists, :list_type
+ end
+
+ def down
+ remove_concurrent_index :lists, :list_type
+ end
+end
diff --git a/db/post_migrate/20180826111825_recalculate_site_statistics.rb b/db/post_migrate/20180826111825_recalculate_site_statistics.rb
new file mode 100644
index 00000000000..741035a444f
--- /dev/null
+++ b/db/post_migrate/20180826111825_recalculate_site_statistics.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class RecalculateSiteStatistics < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ transaction do
+ execute('SET LOCAL statement_timeout TO 0') if Gitlab::Database.postgresql? # see https://gitlab.com/gitlab-org/gitlab-ce/issues/48967
+
+ execute("UPDATE site_statistics SET repositories_count = (SELECT COUNT(*) FROM projects)")
+ end
+
+ transaction do
+ execute('SET LOCAL statement_timeout TO 0') if Gitlab::Database.postgresql? # see https://gitlab.com/gitlab-org/gitlab-ce/issues/48967
+
+ execute("UPDATE site_statistics SET wikis_count = (SELECT COUNT(*) FROM project_features WHERE wiki_access_level != 0)")
+ end
+ end
+
+ def down
+ # No downside in keeping the counter up-to-date
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6168a1be29e..cb8f90efded 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180816193530) do
+ActiveRecord::Schema.define(version: 20180826111825) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -1135,6 +1135,7 @@ ActiveRecord::Schema.define(version: 20180816193530) do
add_index "lists", ["board_id", "label_id"], name: "index_lists_on_board_id_and_label_id", unique: true, using: :btree
add_index "lists", ["label_id"], name: "index_lists_on_label_id", using: :btree
+ add_index "lists", ["list_type"], name: "index_lists_on_list_type", using: :btree
create_table "members", force: :cascade do |t|
t.integer "access_level", null: false
@@ -1740,6 +1741,7 @@ ActiveRecord::Schema.define(version: 20180816193530) do
t.datetime "updated_at", null: false
end
+ add_index "protected_tags", ["project_id", "name"], name: "index_protected_tags_on_project_id_and_name", unique: true, using: :btree
add_index "protected_tags", ["project_id"], name: "index_protected_tags_on_project_id", using: :btree
create_table "push_event_payloads", id: false, force: :cascade do |t|
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png
index 11ce324f938..223fd0ac401 100644
--- a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png
+++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png
Binary files differ
diff --git a/doc/administration/auth/img/crowd_application.png b/doc/administration/auth/img/crowd_application.png
index 7deea9dac8e..5029a005667 100644
--- a/doc/administration/auth/img/crowd_application.png
+++ b/doc/administration/auth/img/crowd_application.png
Binary files differ
diff --git a/doc/administration/auth/img/crowd_application_authorisation.png b/doc/administration/auth/img/crowd_application_authorisation.png
index 70339891b34..0e0bde1344b 100644
--- a/doc/administration/auth/img/crowd_application_authorisation.png
+++ b/doc/administration/auth/img/crowd_application_authorisation.png
Binary files differ
diff --git a/doc/administration/img/circuitbreaker_config.png b/doc/administration/img/circuitbreaker_config.png
index 693b2ee9c69..20233276055 100644
--- a/doc/administration/img/circuitbreaker_config.png
+++ b/doc/administration/img/circuitbreaker_config.png
Binary files differ
diff --git a/doc/administration/img/custom_hooks_error_msg.png b/doc/administration/img/custom_hooks_error_msg.png
index 1b3277bef16..845f0de19ce 100644
--- a/doc/administration/img/custom_hooks_error_msg.png
+++ b/doc/administration/img/custom_hooks_error_msg.png
Binary files differ
diff --git a/doc/administration/img/failing_storage.png b/doc/administration/img/failing_storage.png
index 82b393a58b2..652d7dcb5d7 100644
--- a/doc/administration/img/failing_storage.png
+++ b/doc/administration/img/failing_storage.png
Binary files differ
diff --git a/doc/administration/img/integration/plantuml-example.png b/doc/administration/img/integration/plantuml-example.png
index cb64eca1a8a..3e0d6389cbd 100644
--- a/doc/administration/img/integration/plantuml-example.png
+++ b/doc/administration/img/integration/plantuml-example.png
Binary files differ
diff --git a/doc/administration/img/repository_storages_admin_ui.png b/doc/administration/img/repository_storages_admin_ui.png
index 036e708cdac..5f1b4936704 100644
--- a/doc/administration/img/repository_storages_admin_ui.png
+++ b/doc/administration/img/repository_storages_admin_ui.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/grafana_dashboard_import.png b/doc/administration/monitoring/performance/img/grafana_dashboard_import.png
index 7761ea00522..fd639ee0eb8 100644
--- a/doc/administration/monitoring/performance/img/grafana_dashboard_import.png
+++ b/doc/administration/monitoring/performance/img/grafana_dashboard_import.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/grafana_data_source_configuration.png b/doc/administration/monitoring/performance/img/grafana_data_source_configuration.png
index 3e749eb8f9d..a98e0ed1e7d 100644
--- a/doc/administration/monitoring/performance/img/grafana_data_source_configuration.png
+++ b/doc/administration/monitoring/performance/img/grafana_data_source_configuration.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/grafana_data_source_empty.png b/doc/administration/monitoring/performance/img/grafana_data_source_empty.png
index 33fcaaaef64..549ada8343e 100644
--- a/doc/administration/monitoring/performance/img/grafana_data_source_empty.png
+++ b/doc/administration/monitoring/performance/img/grafana_data_source_empty.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/grafana_save_icon.png b/doc/administration/monitoring/performance/img/grafana_save_icon.png
index c18f2147e9d..68a071f5ae2 100644
--- a/doc/administration/monitoring/performance/img/grafana_save_icon.png
+++ b/doc/administration/monitoring/performance/img/grafana_save_icon.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png
index 48212f6276a..2bf686f9017 100644
--- a/doc/administration/monitoring/performance/img/performance_bar.png
+++ b/doc/administration/monitoring/performance/img/performance_bar.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/performance_bar_configuration_settings.png b/doc/administration/monitoring/performance/img/performance_bar_configuration_settings.png
index 2d64ef8c5fc..fafc50cd000 100644
--- a/doc/administration/monitoring/performance/img/performance_bar_configuration_settings.png
+++ b/doc/administration/monitoring/performance/img/performance_bar_configuration_settings.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png
index 52176df9ecd..7af6d401d1d 100644
--- a/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png
+++ b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/performance_bar_line_profiling.png b/doc/administration/monitoring/performance/img/performance_bar_line_profiling.png
index 7868e2c46d1..a55ce753101 100644
--- a/doc/administration/monitoring/performance/img/performance_bar_line_profiling.png
+++ b/doc/administration/monitoring/performance/img/performance_bar_line_profiling.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png
index 372ae021f6b..b3219b4fa94 100644
--- a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png
+++ b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/request_profile_result.png b/doc/administration/monitoring/performance/img/request_profile_result.png
index 8ebd74c2d3c..1b06e240fa0 100644
--- a/doc/administration/monitoring/performance/img/request_profile_result.png
+++ b/doc/administration/monitoring/performance/img/request_profile_result.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/request_profiling_token.png b/doc/administration/monitoring/performance/img/request_profiling_token.png
index 9160407e028..8c4109c17f0 100644
--- a/doc/administration/monitoring/performance/img/request_profiling_token.png
+++ b/doc/administration/monitoring/performance/img/request_profiling_token.png
Binary files differ
diff --git a/doc/administration/operations/img/sidekiq_job_throttling.png b/doc/administration/operations/img/sidekiq_job_throttling.png
index dcf40b4bf17..abd09f3b115 100644
--- a/doc/administration/operations/img/sidekiq_job_throttling.png
+++ b/doc/administration/operations/img/sidekiq_job_throttling.png
Binary files differ
diff --git a/doc/administration/operations/img/write_to_authorized_keys_setting.png b/doc/administration/operations/img/write_to_authorized_keys_setting.png
index 232765f1917..f6227a6057b 100644
--- a/doc/administration/operations/img/write_to_authorized_keys_setting.png
+++ b/doc/administration/operations/img/write_to_authorized_keys_setting.png
Binary files differ
diff --git a/doc/api/README.md b/doc/api/README.md
index 45e926d3b6b..e2a6e87a2c3 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -53,6 +53,7 @@ following locations:
- [Project Members](members.md)
- [Project Snippets](project_snippets.md)
- [Protected Branches](protected_branches.md)
+- [Protected Tags](protected_tags.md)
- [Repositories](repositories.md)
- [Repository Files](repository_files.md)
- [Runners](runners.md)
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index 65e2f9d6cd9..a1e1ff1419d 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -136,7 +136,7 @@ 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 |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions?body=comment
@@ -159,7 +159,7 @@ Parameters:
| `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 |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
@@ -342,7 +342,7 @@ 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 |
| `body` | string | yes | The content of a discussion |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions?body=comment
@@ -365,7 +365,7 @@ Parameters:
| `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 |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
@@ -601,7 +601,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 |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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 |
| `position[start_sha]` | string | yes | SHA referencing commit in target branch |
@@ -659,7 +659,7 @@ Parameters:
| `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 |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
@@ -894,7 +894,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 |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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 |
| `position[start_sha]` | string | yes | SHA referencing commit in target branch |
@@ -930,7 +930,7 @@ Parameters:
| `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 |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+| `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: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index 152929b7614..e396f4411e6 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -96,6 +96,19 @@ Parameters:
- `start_date` (optional) - The start date of the milestone
- `state_event` (optional) - The state event of the milestone (close|activate)
+## Delete group milestone
+
+Only for user with developer access to the group.
+
+```
+DELETE /groups/:id/milestones/:milestone_id
+```
+
+Parameters:
+
+- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
+- `milestone_id` (required) - The ID of the group's milestone
+
## Get all issues assigned to a single milestone
Gets all issues assigned to a single group milestone.
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 103eaa5655f..f4c0f4ea65b 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -470,7 +470,7 @@ POST /projects/:id/issues
| `assignee_ids` | Array[integer] | no | The ID of the users to assign issue |
| `milestone_id` | integer | no | The global ID of a milestone to assign issue |
| `labels` | string | no | Comma-separated label names for an issue |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project/group owner rights) |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This will fill the issue with a default description and mark all discussions as resolved. When passing a description or title, these values will take precedence over the default values.|
| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
diff --git a/doc/api/notes.md b/doc/api/notes.md
index c271d46688f..44940bdd9e5 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -100,7 +100,7 @@ Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `issue_id` (required) - The IID of an issue
- `body` (required) - The content of a note
-- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z
+- `created_at` (optional) - 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: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
diff --git a/doc/api/protected_tags.md b/doc/api/protected_tags.md
new file mode 100644
index 00000000000..aa750e467f8
--- /dev/null
+++ b/doc/api/protected_tags.md
@@ -0,0 +1,128 @@
+# Protected tags API
+
+>**Note:** This feature was introduced in GitLab 11.3
+
+**Valid access levels**
+
+Currently, these levels are recognized:
+```
+0 => No access
+30 => Developer access
+40 => Maintainer access
+```
+
+## List protected tags
+
+Gets a list of protected tags from a project.
+This function takes pagination parameters `page` and `per_page` to restrict the list of protected tags.
+
+```
+GET /projects/:id/protected_tags
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags'
+```
+
+Example response:
+
+```json
+[
+ {
+ "name": "release-1-0",
+ "create_access_levels": [
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers"
+ }
+ ]
+ },
+ ...
+]
+```
+
+## Get a single protected tag or wildcard protected tag
+
+Gets a single protected tag or wildcard protected tag.
+The pagination parameters `page` and `per_page` can be used to restrict the list of protected tags.
+
+```
+GET /projects/:id/protected_tags/:name
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `name` | string | yes | The name of the tag or wildcard |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags/release-1-0'
+```
+
+Example response:
+
+```json
+{
+ "name": "release-1-0",
+ "create_access_levels": [
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers"
+ }
+ ]
+}
+```
+
+## Protect repository tags
+
+Protects a single repository tag or several project repository
+tags using a wildcard protected tag.
+
+```
+POST /projects/:id/protected_tags
+```
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags?name=*-stable&create_access_level=30'
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `name` | string | yes | The name of the tag or wildcard |
+| `create_access_level` | string | no | Access levels allowed to create (defaults: `40`, maintainer access level) |
+
+Example response:
+
+```json
+{
+ "name": "*-stable",
+ "create_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ]
+}
+```
+
+## Unprotect repository tags
+
+Unprotects the given protected tag or wildcard protected tag.
+
+```
+DELETE /projects/:id/protected_tags/:name
+```
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags/*-stable'
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `name` | string | yes | The name of the tag |
diff --git a/doc/ci/autodeploy/img/auto_deploy_btn.png b/doc/ci/autodeploy/img/auto_deploy_btn.png
index 25915ed1c9d..ee88e5ce8c0 100644
--- a/doc/ci/autodeploy/img/auto_deploy_btn.png
+++ b/doc/ci/autodeploy/img/auto_deploy_btn.png
Binary files differ
diff --git a/doc/ci/autodeploy/img/auto_deploy_button.png b/doc/ci/autodeploy/img/auto_deploy_button.png
index 423e76a6cda..0e84d9c57a1 100644
--- a/doc/ci/autodeploy/img/auto_deploy_button.png
+++ b/doc/ci/autodeploy/img/auto_deploy_button.png
Binary files differ
diff --git a/doc/ci/autodeploy/img/auto_deploy_dropdown.png b/doc/ci/autodeploy/img/auto_deploy_dropdown.png
index 5815937a4af..4094f8ebb4e 100644
--- a/doc/ci/autodeploy/img/auto_deploy_dropdown.png
+++ b/doc/ci/autodeploy/img/auto_deploy_dropdown.png
Binary files differ
diff --git a/doc/ci/autodeploy/img/auto_monitoring.png b/doc/ci/autodeploy/img/auto_monitoring.png
index 5661b50841b..5a11923d199 100644
--- a/doc/ci/autodeploy/img/auto_monitoring.png
+++ b/doc/ci/autodeploy/img/auto_monitoring.png
Binary files differ
diff --git a/doc/ci/autodeploy/img/guide_connect_cluster.png b/doc/ci/autodeploy/img/guide_connect_cluster.png
index b856b81a1d0..703d536f37a 100644
--- a/doc/ci/autodeploy/img/guide_connect_cluster.png
+++ b/doc/ci/autodeploy/img/guide_connect_cluster.png
Binary files differ
diff --git a/doc/ci/autodeploy/img/guide_integration.png b/doc/ci/autodeploy/img/guide_integration.png
index 723b2619ea2..ab72de2bba3 100644
--- a/doc/ci/autodeploy/img/guide_integration.png
+++ b/doc/ci/autodeploy/img/guide_integration.png
Binary files differ
diff --git a/doc/ci/autodeploy/img/guide_secret.png b/doc/ci/autodeploy/img/guide_secret.png
index 01f5aa49908..8469bee48b7 100644
--- a/doc/ci/autodeploy/img/guide_secret.png
+++ b/doc/ci/autodeploy/img/guide_secret.png
Binary files differ
diff --git a/doc/ci/caching/img/clear_runners_cache.png b/doc/ci/caching/img/clear_runners_cache.png
index e5db4a47b3e..4f1171513ad 100644
--- a/doc/ci/caching/img/clear_runners_cache.png
+++ b/doc/ci/caching/img/clear_runners_cache.png
Binary files differ
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.png b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.png
index 76e0295722b..09eef98202f 100644
--- a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.png
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.png
Binary files differ
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.png b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.png
index 050a97d2726..71ffcdea289 100644
--- a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.png
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.png
Binary files differ
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.png b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.png
index 4ab5d5f401a..a9452577a42 100644
--- a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.png
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png
index b1406fed6b8..704d43ea52e 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png
index 9aae11b8679..763ce48fa5a 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png
index a06b6d417cd..f299d6355cb 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png
index d357ecda7d2..9c301e1fc8c 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png
index baf8dec499c..2f451615a3a 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png
index d96c43bcf16..a5fd6b020d1 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png
index 997db10189f..1f605504171 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png
Binary files differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png
index 658c0b5bcac..b7906d49dcb 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png
Binary files differ
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/job-succeeded.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/job-succeeded.png
index 0f94ac60fee..77b05f55f88 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/job-succeeded.png
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/job-succeeded.png
Binary files differ
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.png
index 94828a20f51..04d3dc40fa5 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.png
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.png
Binary files differ
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.png
index 68503b392ed..63812b41c2c 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.png
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.png
Binary files differ
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.png
index d73140ccdd9..c0daa1a6a91 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.png
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.png
Binary files differ
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select-template.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select-template.png
index 38bfde0a3dd..727995f463c 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select-template.png
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select-template.png
Binary files differ
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/setup-ci.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/setup-ci.png
index bfe85c6a10b..50c6ca593c1 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/setup-ci.png
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/setup-ci.png
Binary files differ
diff --git a/doc/ci/img/deployments_view.png b/doc/ci/img/deployments_view.png
index 436fed5f465..45d882b536c 100644
--- a/doc/ci/img/deployments_view.png
+++ b/doc/ci/img/deployments_view.png
Binary files differ
diff --git a/doc/ci/img/environments_available.png b/doc/ci/img/environments_available.png
index 2991a309655..7ab92838ece 100644
--- a/doc/ci/img/environments_available.png
+++ b/doc/ci/img/environments_available.png
Binary files differ
diff --git a/doc/ci/img/environments_dynamic_groups.png b/doc/ci/img/environments_dynamic_groups.png
index 45124b3d8d8..37828ccd0c1 100644
--- a/doc/ci/img/environments_dynamic_groups.png
+++ b/doc/ci/img/environments_dynamic_groups.png
Binary files differ
diff --git a/doc/ci/img/environments_link_url_mr.png b/doc/ci/img/environments_link_url_mr.png
index 7ce46063062..75d7311b862 100644
--- a/doc/ci/img/environments_link_url_mr.png
+++ b/doc/ci/img/environments_link_url_mr.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_deployments.png b/doc/ci/img/environments_manual_action_deployments.png
index 93beaa0de54..c5959c0003e 100644
--- a/doc/ci/img/environments_manual_action_deployments.png
+++ b/doc/ci/img/environments_manual_action_deployments.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_environments.png b/doc/ci/img/environments_manual_action_environments.png
index 9490be63f14..b2ec27cc721 100644
--- a/doc/ci/img/environments_manual_action_environments.png
+++ b/doc/ci/img/environments_manual_action_environments.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_jobs.png b/doc/ci/img/environments_manual_action_jobs.png
index 9ae223cf77f..d948ee5da9e 100644
--- a/doc/ci/img/environments_manual_action_jobs.png
+++ b/doc/ci/img/environments_manual_action_jobs.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_pipelines.png b/doc/ci/img/environments_manual_action_pipelines.png
index 129e44f6fb0..332850afb7f 100644
--- a/doc/ci/img/environments_manual_action_pipelines.png
+++ b/doc/ci/img/environments_manual_action_pipelines.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_single_pipeline.png b/doc/ci/img/environments_manual_action_single_pipeline.png
index 1eeb4379eb7..8c1c0c1d993 100644
--- a/doc/ci/img/environments_manual_action_single_pipeline.png
+++ b/doc/ci/img/environments_manual_action_single_pipeline.png
Binary files differ
diff --git a/doc/ci/img/environments_monitoring.png b/doc/ci/img/environments_monitoring.png
index dcffdd1fdb8..63d272ae42a 100644
--- a/doc/ci/img/environments_monitoring.png
+++ b/doc/ci/img/environments_monitoring.png
Binary files differ
diff --git a/doc/ci/img/environments_mr_review_app.png b/doc/ci/img/environments_mr_review_app.png
index 4bb643d708f..61b7e9fe77c 100644
--- a/doc/ci/img/environments_mr_review_app.png
+++ b/doc/ci/img/environments_mr_review_app.png
Binary files differ
diff --git a/doc/ci/img/environments_terminal_button_on_index.png b/doc/ci/img/environments_terminal_button_on_index.png
index 061bb7c3c87..40110ff325f 100644
--- a/doc/ci/img/environments_terminal_button_on_index.png
+++ b/doc/ci/img/environments_terminal_button_on_index.png
Binary files differ
diff --git a/doc/ci/img/environments_terminal_button_on_show.png b/doc/ci/img/environments_terminal_button_on_show.png
index 4d24304bc93..e96ca9c9c7e 100644
--- a/doc/ci/img/environments_terminal_button_on_show.png
+++ b/doc/ci/img/environments_terminal_button_on_show.png
Binary files differ
diff --git a/doc/ci/img/environments_terminal_page.png b/doc/ci/img/environments_terminal_page.png
index fde1bf325a6..736b2d01a99 100644
--- a/doc/ci/img/environments_terminal_page.png
+++ b/doc/ci/img/environments_terminal_page.png
Binary files differ
diff --git a/doc/ci/img/job_failure_reason.png b/doc/ci/img/job_failure_reason.png
index a60ce1fb21c..d44b8e6d1be 100644
--- a/doc/ci/img/job_failure_reason.png
+++ b/doc/ci/img/job_failure_reason.png
Binary files differ
diff --git a/doc/ci/img/pipelines_grouped.png b/doc/ci/img/pipelines_grouped.png
index 06f52e03320..82814754747 100644
--- a/doc/ci/img/pipelines_grouped.png
+++ b/doc/ci/img/pipelines_grouped.png
Binary files differ
diff --git a/doc/ci/img/pipelines_index.png b/doc/ci/img/pipelines_index.png
index 3b522a9c5e4..e168e7e23df 100644
--- a/doc/ci/img/pipelines_index.png
+++ b/doc/ci/img/pipelines_index.png
Binary files differ
diff --git a/doc/ci/img/pipelines_mini_graph.png b/doc/ci/img/pipelines_mini_graph.png
index 042c8ffeef5..8656b02f60d 100644
--- a/doc/ci/img/pipelines_mini_graph.png
+++ b/doc/ci/img/pipelines_mini_graph.png
Binary files differ
diff --git a/doc/ci/img/pipelines_mini_graph_simple.png b/doc/ci/img/pipelines_mini_graph_simple.png
index eb36c09b2d4..d00a8313088 100644
--- a/doc/ci/img/pipelines_mini_graph_simple.png
+++ b/doc/ci/img/pipelines_mini_graph_simple.png
Binary files differ
diff --git a/doc/ci/img/view_on_env_blob.png b/doc/ci/img/view_on_env_blob.png
index f4fe99046f0..dd9ca40280a 100644
--- a/doc/ci/img/view_on_env_blob.png
+++ b/doc/ci/img/view_on_env_blob.png
Binary files differ
diff --git a/doc/ci/img/view_on_env_mr.png b/doc/ci/img/view_on_env_mr.png
index 47ddb40bdc1..2c0bd25a4f2 100644
--- a/doc/ci/img/view_on_env_mr.png
+++ b/doc/ci/img/view_on_env_mr.png
Binary files differ
diff --git a/doc/ci/interactive_web_terminal/img/interactive_web_terminal_page.png b/doc/ci/interactive_web_terminal/img/interactive_web_terminal_page.png
index b59c1b6bc43..0523e62db70 100644
--- a/doc/ci/interactive_web_terminal/img/interactive_web_terminal_page.png
+++ b/doc/ci/interactive_web_terminal/img/interactive_web_terminal_page.png
Binary files differ
diff --git a/doc/ci/interactive_web_terminal/img/interactive_web_terminal_running_job.png b/doc/ci/interactive_web_terminal/img/interactive_web_terminal_running_job.png
index f92c6df07a1..3ee5e39afc0 100644
--- a/doc/ci/interactive_web_terminal/img/interactive_web_terminal_running_job.png
+++ b/doc/ci/interactive_web_terminal/img/interactive_web_terminal_running_job.png
Binary files differ
diff --git a/doc/ci/quick_start/img/build_log.png b/doc/ci/quick_start/img/build_log.png
index 3a7248ca772..2bf0992c50e 100644
--- a/doc/ci/quick_start/img/build_log.png
+++ b/doc/ci/quick_start/img/build_log.png
Binary files differ
diff --git a/doc/ci/quick_start/img/builds_status.png b/doc/ci/quick_start/img/builds_status.png
index f829240f3b3..58978e23978 100644
--- a/doc/ci/quick_start/img/builds_status.png
+++ b/doc/ci/quick_start/img/builds_status.png
Binary files differ
diff --git a/doc/ci/quick_start/img/new_commit.png b/doc/ci/quick_start/img/new_commit.png
index b3dd848b294..507eb93ac0c 100644
--- a/doc/ci/quick_start/img/new_commit.png
+++ b/doc/ci/quick_start/img/new_commit.png
Binary files differ
diff --git a/doc/ci/review_apps/img/review_apps_preview_in_mr.png b/doc/ci/review_apps/img/review_apps_preview_in_mr.png
index 0300392f24b..7d0923f198f 100644
--- a/doc/ci/review_apps/img/review_apps_preview_in_mr.png
+++ b/doc/ci/review_apps/img/review_apps_preview_in_mr.png
Binary files differ
diff --git a/doc/ci/runners/img/protected_runners_check_box.png b/doc/ci/runners/img/protected_runners_check_box.png
index fb58498c7ce..3c47ebdec29 100644
--- a/doc/ci/runners/img/protected_runners_check_box.png
+++ b/doc/ci/runners/img/protected_runners_check_box.png
Binary files differ
diff --git a/doc/ci/runners/img/shared_runner_ip_address.png b/doc/ci/runners/img/shared_runner_ip_address.png
index 3b1542d59d3..527b4f4043d 100644
--- a/doc/ci/runners/img/shared_runner_ip_address.png
+++ b/doc/ci/runners/img/shared_runner_ip_address.png
Binary files differ
diff --git a/doc/ci/runners/img/specific_runner_ip_address.png b/doc/ci/runners/img/specific_runner_ip_address.png
index 3b4c3e9f2eb..e08663109ba 100644
--- a/doc/ci/runners/img/specific_runner_ip_address.png
+++ b/doc/ci/runners/img/specific_runner_ip_address.png
Binary files differ
diff --git a/doc/ci/triggers/img/builds_page.png b/doc/ci/triggers/img/builds_page.png
index c9cc8f308f4..14d73b140f4 100644
--- a/doc/ci/triggers/img/builds_page.png
+++ b/doc/ci/triggers/img/builds_page.png
Binary files differ
diff --git a/doc/ci/triggers/img/trigger_single_build.png b/doc/ci/triggers/img/trigger_single_build.png
index 837bbeffe9f..b760782afdc 100644
--- a/doc/ci/triggers/img/trigger_single_build.png
+++ b/doc/ci/triggers/img/trigger_single_build.png
Binary files differ
diff --git a/doc/customization/branded_login_page/custom_sign_in.png b/doc/customization/branded_login_page/custom_sign_in.png
index c0888fe1f18..03ea5281ebe 100644
--- a/doc/customization/branded_login_page/custom_sign_in.png
+++ b/doc/customization/branded_login_page/custom_sign_in.png
Binary files differ
diff --git a/doc/customization/branded_page_and_email_header/appearance.png b/doc/customization/branded_page_and_email_header/appearance.png
index abbba6f9ac9..6b79bc47005 100644
--- a/doc/customization/branded_page_and_email_header/appearance.png
+++ b/doc/customization/branded_page_and_email_header/appearance.png
Binary files differ
diff --git a/doc/customization/branded_page_and_email_header/custom_brand_header.png b/doc/customization/branded_page_and_email_header/custom_brand_header.png
index 7390f8a5e4e..d779236bbe7 100644
--- a/doc/customization/branded_page_and_email_header/custom_brand_header.png
+++ b/doc/customization/branded_page_and_email_header/custom_brand_header.png
Binary files differ
diff --git a/doc/customization/branded_page_and_email_header/custom_email_header.png b/doc/customization/branded_page_and_email_header/custom_email_header.png
index 705698ef4a8..729b166364b 100644
--- a/doc/customization/branded_page_and_email_header/custom_email_header.png
+++ b/doc/customization/branded_page_and_email_header/custom_email_header.png
Binary files differ
diff --git a/doc/customization/favicon/appearance.png b/doc/customization/favicon/appearance.png
index 6c41a05fc1f..da1002826dd 100644
--- a/doc/customization/favicon/appearance.png
+++ b/doc/customization/favicon/appearance.png
Binary files differ
diff --git a/doc/customization/favicon/custom_favicon.png b/doc/customization/favicon/custom_favicon.png
index fa1b8827a36..20dddfbea33 100644
--- a/doc/customization/favicon/custom_favicon.png
+++ b/doc/customization/favicon/custom_favicon.png
Binary files differ
diff --git a/doc/customization/new_project_page/appearance_settings.png b/doc/customization/new_project_page/appearance_settings.png
index 08eea684e14..4fcdd1caa21 100644
--- a/doc/customization/new_project_page/appearance_settings.png
+++ b/doc/customization/new_project_page/appearance_settings.png
Binary files differ
diff --git a/doc/customization/new_project_page/custom_new_project_page.png b/doc/customization/new_project_page/custom_new_project_page.png
index 662c715f193..c6f7839e9c3 100644
--- a/doc/customization/new_project_page/custom_new_project_page.png
+++ b/doc/customization/new_project_page/custom_new_project_page.png
Binary files differ
diff --git a/doc/customization/new_project_page/default_new_project_page.png b/doc/customization/new_project_page/default_new_project_page.png
index 4a0bcf09903..f5b209ac5ea 100644
--- a/doc/customization/new_project_page/default_new_project_page.png
+++ b/doc/customization/new_project_page/default_new_project_page.png
Binary files differ
diff --git a/doc/development/README.md b/doc/development/README.md
index ee9a9852205..20f8fa1d368 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -54,6 +54,7 @@ description: 'Learn how to contribute to GitLab.'
- [Performance guidelines](performance.md)
- [Merge request performance guidelines](merge_request_performance_guidelines.md)
for ensuring merge requests do not negatively impact GitLab performance
+- [Profiling](profiling.md) for profiling a URL
## Database guides
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 3e417a44ec1..66d8a4f2f6e 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -70,7 +70,7 @@ The add-on component gitlab-shell serves repositories over SSH. It manages the S
Gitaly executes git operations from gitlab-shell and the GitLab web app, and provides an API to the GitLab web app to get attributes from git (e.g. title, branches, tags, other meta data), and to get blobs (e.g. diffs, commits, files).
-You may also be interested in the [production architecture of GitLab.com](https://about.gitlab.com/handbook/infrastructure/production-architecture/).
+You may also be interested in the [production architecture of GitLab.com](https://about.gitlab.com/handbook/engineering/infrastructure/production-architecture/).
### Installation Folder Summary
diff --git a/doc/development/documentation/img/manual_build_docs.png b/doc/development/documentation/img/manual_build_docs.png
index 615facabb5f..e366a2f7ec4 100644
--- a/doc/development/documentation/img/manual_build_docs.png
+++ b/doc/development/documentation/img/manual_build_docs.png
Binary files differ
diff --git a/doc/development/fe_guide/img/boards_diagram.png b/doc/development/fe_guide/img/boards_diagram.png
index 7a2cf972fd0..856c9b05bbf 100644
--- a/doc/development/fe_guide/img/boards_diagram.png
+++ b/doc/development/fe_guide/img/boards_diagram.png
Binary files differ
diff --git a/doc/development/fe_guide/img/gl-modal.png b/doc/development/fe_guide/img/gl-modal.png
index 47302e857bc..b2d2d637e57 100644
--- a/doc/development/fe_guide/img/gl-modal.png
+++ b/doc/development/fe_guide/img/gl-modal.png
Binary files differ
diff --git a/doc/development/feature_flags.md b/doc/development/feature_flags.md
index 09ea8c05be6..702caacc74f 100644
--- a/doc/development/feature_flags.md
+++ b/doc/development/feature_flags.md
@@ -57,3 +57,15 @@ end
Features that are developed and are intended to be merged behind a feature flag
should not include a changelog entry. The entry should be added in the merge
request removing the feature flags.
+
+### Specs
+
+In the test environment `Feature.enabled?` is stubbed to always respond to `true`,
+so we make sure behavior under feature flag doesn't go untested in some non-specific
+contexts.
+
+If you need to test the feature flag in a different state, you need to stub it with:
+
+```ruby
+stub_feature_flags(my_feature_flag: false)
+```
diff --git a/doc/development/gitlab_architecture_diagram.png b/doc/development/gitlab_architecture_diagram.png
index 378f7384574..90e27d5462a 100644
--- a/doc/development/gitlab_architecture_diagram.png
+++ b/doc/development/gitlab_architecture_diagram.png
Binary files differ
diff --git a/doc/development/img/trigger_ss1.png b/doc/development/img/trigger_ss1.png
index ccff1009a25..addbc551f73 100644
--- a/doc/development/img/trigger_ss1.png
+++ b/doc/development/img/trigger_ss1.png
Binary files differ
diff --git a/doc/development/img/trigger_ss2.png b/doc/development/img/trigger_ss2.png
index 94dfd048793..02ef3810a59 100644
--- a/doc/development/img/trigger_ss2.png
+++ b/doc/development/img/trigger_ss2.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-close--active.png b/doc/development/ux_guide/img/button-close--active.png
index 824bfc8f31b..97a5301fb91 100644
--- a/doc/development/ux_guide/img/button-close--active.png
+++ b/doc/development/ux_guide/img/button-close--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-close--hover.png b/doc/development/ux_guide/img/button-close--hover.png
index 0291e121894..6b8fdf5695b 100644
--- a/doc/development/ux_guide/img/button-close--hover.png
+++ b/doc/development/ux_guide/img/button-close--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-close--resting.png b/doc/development/ux_guide/img/button-close--resting.png
index 986d7174ce7..5679b51687c 100644
--- a/doc/development/ux_guide/img/button-close--resting.png
+++ b/doc/development/ux_guide/img/button-close--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-danger--active.png b/doc/development/ux_guide/img/button-danger--active.png
index d3c64424b26..6a9aab0fcc2 100644
--- a/doc/development/ux_guide/img/button-danger--active.png
+++ b/doc/development/ux_guide/img/button-danger--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-danger--hover.png b/doc/development/ux_guide/img/button-danger--hover.png
index 8506e093306..13e21c28779 100644
--- a/doc/development/ux_guide/img/button-danger--hover.png
+++ b/doc/development/ux_guide/img/button-danger--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-danger--resting.png b/doc/development/ux_guide/img/button-danger--resting.png
index 69ad6bb796b..0ff192bc463 100644
--- a/doc/development/ux_guide/img/button-danger--resting.png
+++ b/doc/development/ux_guide/img/button-danger--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-info--active.png b/doc/development/ux_guide/img/button-info--active.png
index 23be20b225c..12ecdc72a31 100644
--- a/doc/development/ux_guide/img/button-info--active.png
+++ b/doc/development/ux_guide/img/button-info--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-info--hover.png b/doc/development/ux_guide/img/button-info--hover.png
index 4cb4e38558c..3bf93bf2b32 100644
--- a/doc/development/ux_guide/img/button-info--hover.png
+++ b/doc/development/ux_guide/img/button-info--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-info--resting.png b/doc/development/ux_guide/img/button-info--resting.png
index 5883340aa83..a37a37033bf 100644
--- a/doc/development/ux_guide/img/button-info--resting.png
+++ b/doc/development/ux_guide/img/button-info--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-spam--active.png b/doc/development/ux_guide/img/button-spam--active.png
index 55b44898684..a9e115f49c1 100644
--- a/doc/development/ux_guide/img/button-spam--active.png
+++ b/doc/development/ux_guide/img/button-spam--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-spam--hover.png b/doc/development/ux_guide/img/button-spam--hover.png
index 3dc8ed34c54..3b2c16430a6 100644
--- a/doc/development/ux_guide/img/button-spam--hover.png
+++ b/doc/development/ux_guide/img/button-spam--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-spam--resting.png b/doc/development/ux_guide/img/button-spam--resting.png
index b6bf10a5b64..4f9f18ca68a 100644
--- a/doc/development/ux_guide/img/button-spam--resting.png
+++ b/doc/development/ux_guide/img/button-spam--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success--active.png b/doc/development/ux_guide/img/button-success--active.png
index 895a52831cb..b99f6f5e70e 100644
--- a/doc/development/ux_guide/img/button-success--active.png
+++ b/doc/development/ux_guide/img/button-success--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success--hover.png b/doc/development/ux_guide/img/button-success--hover.png
index e4c74bd9778..0d0a61c679a 100644
--- a/doc/development/ux_guide/img/button-success--hover.png
+++ b/doc/development/ux_guide/img/button-success--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success--resting.png b/doc/development/ux_guide/img/button-success--resting.png
index 2fa971b5347..53b955c650a 100644
--- a/doc/development/ux_guide/img/button-success--resting.png
+++ b/doc/development/ux_guide/img/button-success--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success-secondary--active.png b/doc/development/ux_guide/img/button-success-secondary--active.png
index e7383b36946..333a91f2217 100644
--- a/doc/development/ux_guide/img/button-success-secondary--active.png
+++ b/doc/development/ux_guide/img/button-success-secondary--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success-secondary--hover.png b/doc/development/ux_guide/img/button-success-secondary--hover.png
index 4af2a68cf1b..0cce59212e3 100644
--- a/doc/development/ux_guide/img/button-success-secondary--hover.png
+++ b/doc/development/ux_guide/img/button-success-secondary--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success-secondary--resting.png b/doc/development/ux_guide/img/button-success-secondary--resting.png
index a5a4ec512c8..2779a4949f8 100644
--- a/doc/development/ux_guide/img/button-success-secondary--resting.png
+++ b/doc/development/ux_guide/img/button-success-secondary--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-warning--active.png b/doc/development/ux_guide/img/button-warning--active.png
index 5877d46c94d..f5760cd7c12 100644
--- a/doc/development/ux_guide/img/button-warning--active.png
+++ b/doc/development/ux_guide/img/button-warning--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-warning--hover.png b/doc/development/ux_guide/img/button-warning--hover.png
index 308e1adc8a3..a1f4c5cbcc6 100644
--- a/doc/development/ux_guide/img/button-warning--hover.png
+++ b/doc/development/ux_guide/img/button-warning--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-warning--resting.png b/doc/development/ux_guide/img/button-warning--resting.png
index 28e5e601520..3d62fed5930 100644
--- a/doc/development/ux_guide/img/button-warning--resting.png
+++ b/doc/development/ux_guide/img/button-warning--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-blue.png b/doc/development/ux_guide/img/color-blue.png
index 844e926f1f5..77c1a2cab31 100644
--- a/doc/development/ux_guide/img/color-blue.png
+++ b/doc/development/ux_guide/img/color-blue.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-green.png b/doc/development/ux_guide/img/color-green.png
index 5c4c23c7067..51600584c96 100644
--- a/doc/development/ux_guide/img/color-green.png
+++ b/doc/development/ux_guide/img/color-green.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-grey.png b/doc/development/ux_guide/img/color-grey.png
index 5247649a0ce..f0f0b9d80bb 100644
--- a/doc/development/ux_guide/img/color-grey.png
+++ b/doc/development/ux_guide/img/color-grey.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-orange.png b/doc/development/ux_guide/img/color-orange.png
index 1103c715225..f16435c0a64 100644
--- a/doc/development/ux_guide/img/color-orange.png
+++ b/doc/development/ux_guide/img/color-orange.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-red.png b/doc/development/ux_guide/img/color-red.png
index 77ecbbc0a20..5008e75da78 100644
--- a/doc/development/ux_guide/img/color-red.png
+++ b/doc/development/ux_guide/img/color-red.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-anchorlinks.png b/doc/development/ux_guide/img/components-anchorlinks.png
index 4a9c730566c..bd8d30f5905 100644
--- a/doc/development/ux_guide/img/components-anchorlinks.png
+++ b/doc/development/ux_guide/img/components-anchorlinks.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-coverblock.png b/doc/development/ux_guide/img/components-coverblock.png
index fb135f9648a..61160de5613 100644
--- a/doc/development/ux_guide/img/components-coverblock.png
+++ b/doc/development/ux_guide/img/components-coverblock.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-dateexact.png b/doc/development/ux_guide/img/components-dateexact.png
index 686ca727293..cc1fb8216bf 100644
--- a/doc/development/ux_guide/img/components-dateexact.png
+++ b/doc/development/ux_guide/img/components-dateexact.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-fileholder.png b/doc/development/ux_guide/img/components-fileholder.png
index ec2911a1232..5bf8565346a 100644
--- a/doc/development/ux_guide/img/components-fileholder.png
+++ b/doc/development/ux_guide/img/components-fileholder.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-horizontalform.png b/doc/development/ux_guide/img/components-horizontalform.png
index c57dceda43a..e6cbc69d20a 100644
--- a/doc/development/ux_guide/img/components-horizontalform.png
+++ b/doc/development/ux_guide/img/components-horizontalform.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-listinsidepanel.png b/doc/development/ux_guide/img/components-listinsidepanel.png
index 3a72d39bb5d..6b773a19954 100644
--- a/doc/development/ux_guide/img/components-listinsidepanel.png
+++ b/doc/development/ux_guide/img/components-listinsidepanel.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-listwithhover.png b/doc/development/ux_guide/img/components-listwithhover.png
index 8521a8ad53e..0826848ff34 100644
--- a/doc/development/ux_guide/img/components-listwithhover.png
+++ b/doc/development/ux_guide/img/components-listwithhover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-referencehover.png b/doc/development/ux_guide/img/components-referencehover.png
index f80564dbb16..af5405d3e0b 100644
--- a/doc/development/ux_guide/img/components-referencehover.png
+++ b/doc/development/ux_guide/img/components-referencehover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-referenceissues.png b/doc/development/ux_guide/img/components-referenceissues.png
index 51fb2cf3e43..4e175dc169d 100644
--- a/doc/development/ux_guide/img/components-referenceissues.png
+++ b/doc/development/ux_guide/img/components-referenceissues.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-referencelabels.png b/doc/development/ux_guide/img/components-referencelabels.png
index aba450cc3ba..29a985bbaa0 100644
--- a/doc/development/ux_guide/img/components-referencelabels.png
+++ b/doc/development/ux_guide/img/components-referencelabels.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-referencemilestone.png b/doc/development/ux_guide/img/components-referencemilestone.png
index adf2555ccf8..47c76a9d60f 100644
--- a/doc/development/ux_guide/img/components-referencemilestone.png
+++ b/doc/development/ux_guide/img/components-referencemilestone.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-referencemrs.png b/doc/development/ux_guide/img/components-referencemrs.png
index 6c3375f1ea1..9a5032a1516 100644
--- a/doc/development/ux_guide/img/components-referencemrs.png
+++ b/doc/development/ux_guide/img/components-referencemrs.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-referencepeople.png b/doc/development/ux_guide/img/components-referencepeople.png
index b8dd431e2e6..f9ef11be853 100644
--- a/doc/development/ux_guide/img/components-referencepeople.png
+++ b/doc/development/ux_guide/img/components-referencepeople.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-searchbox.png b/doc/development/ux_guide/img/components-searchbox.png
index a25189296ba..5c19024bfb0 100644
--- a/doc/development/ux_guide/img/components-searchbox.png
+++ b/doc/development/ux_guide/img/components-searchbox.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-searchboxscoped.png b/doc/development/ux_guide/img/components-searchboxscoped.png
index b116d714848..d4a35977658 100644
--- a/doc/development/ux_guide/img/components-searchboxscoped.png
+++ b/doc/development/ux_guide/img/components-searchboxscoped.png
Binary files differ
diff --git a/doc/development/ux_guide/img/components-simplelist.png b/doc/development/ux_guide/img/components-simplelist.png
index 858e5064c25..8d11c674e84 100644
--- a/doc/development/ux_guide/img/components-simplelist.png
+++ b/doc/development/ux_guide/img/components-simplelist.png
Binary files differ
diff --git a/doc/development/ux_guide/img/features-contextualnav.png b/doc/development/ux_guide/img/features-contextualnav.png
index f8466f28627..aa816776fad 100644
--- a/doc/development/ux_guide/img/features-contextualnav.png
+++ b/doc/development/ux_guide/img/features-contextualnav.png
Binary files differ
diff --git a/doc/development/ux_guide/img/features-emptystates.png b/doc/development/ux_guide/img/features-emptystates.png
index 51835a7080b..50f31f5e523 100644
--- a/doc/development/ux_guide/img/features-emptystates.png
+++ b/doc/development/ux_guide/img/features-emptystates.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-add.png b/doc/development/ux_guide/img/icon-add.png
index bcad5e84591..f66525cc1b4 100644
--- a/doc/development/ux_guide/img/icon-add.png
+++ b/doc/development/ux_guide/img/icon-add.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-close.png b/doc/development/ux_guide/img/icon-close.png
index dfe1495f5fa..af6c30ebe6a 100644
--- a/doc/development/ux_guide/img/icon-close.png
+++ b/doc/development/ux_guide/img/icon-close.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-edit.png b/doc/development/ux_guide/img/icon-edit.png
index 50f6f841868..b9649f4aeec 100644
--- a/doc/development/ux_guide/img/icon-edit.png
+++ b/doc/development/ux_guide/img/icon-edit.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-notification.png b/doc/development/ux_guide/img/icon-notification.png
index 6ddfaa44f66..5cf8f8ab59a 100644
--- a/doc/development/ux_guide/img/icon-notification.png
+++ b/doc/development/ux_guide/img/icon-notification.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-rss.png b/doc/development/ux_guide/img/icon-rss.png
index b766488b32d..7e2987a2656 100644
--- a/doc/development/ux_guide/img/icon-rss.png
+++ b/doc/development/ux_guide/img/icon-rss.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-spec.png b/doc/development/ux_guide/img/icon-spec.png
index 56b19610dc1..5bb85c5be98 100644
--- a/doc/development/ux_guide/img/icon-spec.png
+++ b/doc/development/ux_guide/img/icon-spec.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-subscribe.png b/doc/development/ux_guide/img/icon-subscribe.png
index 650168296c6..7e2f5e6a1c6 100644
--- a/doc/development/ux_guide/img/icon-subscribe.png
+++ b/doc/development/ux_guide/img/icon-subscribe.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-trash.png b/doc/development/ux_guide/img/icon-trash.png
index b02178ca992..bc46638fb2e 100644
--- a/doc/development/ux_guide/img/icon-trash.png
+++ b/doc/development/ux_guide/img/icon-trash.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-caps-do.png b/doc/development/ux_guide/img/illustrations-caps-do.png
index 7a2c74382f6..f1030769b94 100644
--- a/doc/development/ux_guide/img/illustrations-caps-do.png
+++ b/doc/development/ux_guide/img/illustrations-caps-do.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-caps-don't.png b/doc/development/ux_guide/img/illustrations-caps-don't.png
index 848f72dbe30..ab7abcaaf6f 100644
--- a/doc/development/ux_guide/img/illustrations-caps-don't.png
+++ b/doc/development/ux_guide/img/illustrations-caps-don't.png
Binary files differ
diff --git a/doc/development/ux_guide/img/james-mackey.png b/doc/development/ux_guide/img/james-mackey.png
index c8f9097f69f..f51a45c437b 100644
--- a/doc/development/ux_guide/img/james-mackey.png
+++ b/doc/development/ux_guide/img/james-mackey.png
Binary files differ
diff --git a/doc/development/ux_guide/img/karolina-plaskaty.png b/doc/development/ux_guide/img/karolina-plaskaty.png
index ae2e98b7bad..d1c9528dd5a 100644
--- a/doc/development/ux_guide/img/karolina-plaskaty.png
+++ b/doc/development/ux_guide/img/karolina-plaskaty.png
Binary files differ
diff --git a/doc/development/ux_guide/img/matthieu-poirier.png b/doc/development/ux_guide/img/matthieu-poirier.png
index dd21948ebe2..0ecc2d670d6 100644
--- a/doc/development/ux_guide/img/matthieu-poirier.png
+++ b/doc/development/ux_guide/img/matthieu-poirier.png
Binary files differ
diff --git a/doc/development/ux_guide/img/modals-general-confimation-dialog.png b/doc/development/ux_guide/img/modals-general-confimation-dialog.png
index 00a17374a0b..4ea0ea10ca7 100644
--- a/doc/development/ux_guide/img/modals-general-confimation-dialog.png
+++ b/doc/development/ux_guide/img/modals-general-confimation-dialog.png
Binary files differ
diff --git a/doc/development/ux_guide/img/modals-layout-for-modals.png b/doc/development/ux_guide/img/modals-layout-for-modals.png
index 6c7bc09e750..c481edd8250 100644
--- a/doc/development/ux_guide/img/modals-layout-for-modals.png
+++ b/doc/development/ux_guide/img/modals-layout-for-modals.png
Binary files differ
diff --git a/doc/development/ux_guide/img/modals-special-confimation-dialog.png b/doc/development/ux_guide/img/modals-special-confimation-dialog.png
index bf1e56326c5..d966010158b 100644
--- a/doc/development/ux_guide/img/modals-special-confimation-dialog.png
+++ b/doc/development/ux_guide/img/modals-special-confimation-dialog.png
Binary files differ
diff --git a/doc/development/ux_guide/img/modals-three-buttons.png b/doc/development/ux_guide/img/modals-three-buttons.png
index 519439e64e4..157d1b650bf 100644
--- a/doc/development/ux_guide/img/modals-three-buttons.png
+++ b/doc/development/ux_guide/img/modals-three-buttons.png
Binary files differ
diff --git a/doc/development/ux_guide/img/nazim-ramesh.png b/doc/development/ux_guide/img/nazim-ramesh.png
index cc3e197679d..dad2b37010b 100644
--- a/doc/development/ux_guide/img/nazim-ramesh.png
+++ b/doc/development/ux_guide/img/nazim-ramesh.png
Binary files differ
diff --git a/doc/development/ux_guide/img/popover-placement-above.png b/doc/development/ux_guide/img/popover-placement-above.png
index 1aa044bfc9c..84c9c878ec2 100644
--- a/doc/development/ux_guide/img/popover-placement-above.png
+++ b/doc/development/ux_guide/img/popover-placement-above.png
Binary files differ
diff --git a/doc/development/ux_guide/img/popover-placement-below.png b/doc/development/ux_guide/img/popover-placement-below.png
index 2d6ab8a1618..f6f18199ab6 100644
--- a/doc/development/ux_guide/img/popover-placement-below.png
+++ b/doc/development/ux_guide/img/popover-placement-below.png
Binary files differ
diff --git a/doc/development/ux_guide/img/surfaces-contentitemtitle.png b/doc/development/ux_guide/img/surfaces-contentitemtitle.png
index 3af0b56c8fb..f6cd212ecfd 100644
--- a/doc/development/ux_guide/img/surfaces-contentitemtitle.png
+++ b/doc/development/ux_guide/img/surfaces-contentitemtitle.png
Binary files differ
diff --git a/doc/development/ux_guide/img/surfaces-systeminformationblock.png b/doc/development/ux_guide/img/surfaces-systeminformationblock.png
index 9f42f1d4dd0..f3313add2b8 100644
--- a/doc/development/ux_guide/img/surfaces-systeminformationblock.png
+++ b/doc/development/ux_guide/img/surfaces-systeminformationblock.png
Binary files differ
diff --git a/doc/development/ux_guide/img/surfaces-ux.png b/doc/development/ux_guide/img/surfaces-ux.png
index 53208727c64..eaa7f70c0c7 100644
--- a/doc/development/ux_guide/img/surfaces-ux.png
+++ b/doc/development/ux_guide/img/surfaces-ux.png
Binary files differ
diff --git a/doc/development/ux_guide/img/tooltip-placement.png b/doc/development/ux_guide/img/tooltip-placement.png
index 061f82e4df0..da49c192878 100644
--- a/doc/development/ux_guide/img/tooltip-placement.png
+++ b/doc/development/ux_guide/img/tooltip-placement.png
Binary files differ
diff --git a/doc/development/ux_guide/img/tooltip-usage.png b/doc/development/ux_guide/img/tooltip-usage.png
index 40c4f051cd0..4f5884c4b48 100644
--- a/doc/development/ux_guide/img/tooltip-usage.png
+++ b/doc/development/ux_guide/img/tooltip-usage.png
Binary files differ
diff --git a/doc/gitlab-basics/img/create_new_project_info.png b/doc/gitlab-basics/img/create_new_project_info.png
index b4119dc046a..2693a7f9a6d 100644
--- a/doc/gitlab-basics/img/create_new_project_info.png
+++ b/doc/gitlab-basics/img/create_new_project_info.png
Binary files differ
diff --git a/doc/gitlab-basics/img/fork_new.png b/doc/gitlab-basics/img/fork_new.png
index fa185fdaca1..7bbc3d8fbae 100644
--- a/doc/gitlab-basics/img/fork_new.png
+++ b/doc/gitlab-basics/img/fork_new.png
Binary files differ
diff --git a/doc/gitlab-basics/img/merge_request_select_branch.png b/doc/gitlab-basics/img/merge_request_select_branch.png
index 57ea0e65f34..b1dec975f9b 100644
--- a/doc/gitlab-basics/img/merge_request_select_branch.png
+++ b/doc/gitlab-basics/img/merge_request_select_branch.png
Binary files differ
diff --git a/doc/gitlab-basics/img/profile_settings.png b/doc/gitlab-basics/img/profile_settings.png
index aaa1a39313d..b91b698fb18 100644
--- a/doc/gitlab-basics/img/profile_settings.png
+++ b/doc/gitlab-basics/img/profile_settings.png
Binary files differ
diff --git a/doc/gitlab-basics/img/profile_settings_ssh_keys_paste_pub.png b/doc/gitlab-basics/img/profile_settings_ssh_keys_paste_pub.png
index 5e501ec86ef..0b1c64a72f3 100644
--- a/doc/gitlab-basics/img/profile_settings_ssh_keys_paste_pub.png
+++ b/doc/gitlab-basics/img/profile_settings_ssh_keys_paste_pub.png
Binary files differ
diff --git a/doc/gitlab-basics/img/profile_settings_ssh_keys_single_key.png b/doc/gitlab-basics/img/profile_settings_ssh_keys_single_key.png
index 7ebb8973ef0..8014f1d5301 100644
--- a/doc/gitlab-basics/img/profile_settings_ssh_keys_single_key.png
+++ b/doc/gitlab-basics/img/profile_settings_ssh_keys_single_key.png
Binary files differ
diff --git a/doc/gitlab-basics/img/profile_settings_ssh_keys_title.png b/doc/gitlab-basics/img/profile_settings_ssh_keys_title.png
index 89a04c17fed..02ca0bf7478 100644
--- a/doc/gitlab-basics/img/profile_settings_ssh_keys_title.png
+++ b/doc/gitlab-basics/img/profile_settings_ssh_keys_title.png
Binary files differ
diff --git a/doc/img/devops_lifecycle.png b/doc/img/devops_lifecycle.png
index 0616be46df8..0b15e9619a5 100644
--- a/doc/img/devops_lifecycle.png
+++ b/doc/img/devops_lifecycle.png
Binary files differ
diff --git a/doc/install/google_cloud_platform/img/boot_disk.png b/doc/install/google_cloud_platform/img/boot_disk.png
index 37b2d9eaae7..b9f7eed6601 100644
--- a/doc/install/google_cloud_platform/img/boot_disk.png
+++ b/doc/install/google_cloud_platform/img/boot_disk.png
Binary files differ
diff --git a/doc/install/google_cloud_platform/img/first_signin.png b/doc/install/google_cloud_platform/img/first_signin.png
index 6eb3392d674..1e218abf63d 100644
--- a/doc/install/google_cloud_platform/img/first_signin.png
+++ b/doc/install/google_cloud_platform/img/first_signin.png
Binary files differ
diff --git a/doc/install/google_cloud_platform/img/gcp_landing.png b/doc/install/google_cloud_platform/img/gcp_landing.png
index d6390c4dd4f..92a9873728c 100644
--- a/doc/install/google_cloud_platform/img/gcp_landing.png
+++ b/doc/install/google_cloud_platform/img/gcp_landing.png
Binary files differ
diff --git a/doc/install/google_cloud_platform/img/launch_vm.png b/doc/install/google_cloud_platform/img/launch_vm.png
index 3fd13f232bb..53cb23277fd 100644
--- a/doc/install/google_cloud_platform/img/launch_vm.png
+++ b/doc/install/google_cloud_platform/img/launch_vm.png
Binary files differ
diff --git a/doc/install/google_cloud_platform/img/ssh_terminal.png b/doc/install/google_cloud_platform/img/ssh_terminal.png
index 6a1a418d8e9..171cb572074 100644
--- a/doc/install/google_cloud_platform/img/ssh_terminal.png
+++ b/doc/install/google_cloud_platform/img/ssh_terminal.png
Binary files differ
diff --git a/doc/install/google_cloud_platform/img/vm_created.png b/doc/install/google_cloud_platform/img/vm_created.png
index fb467f40838..0ba422af60c 100644
--- a/doc/install/google_cloud_platform/img/vm_created.png
+++ b/doc/install/google_cloud_platform/img/vm_created.png
Binary files differ
diff --git a/doc/install/google_cloud_platform/img/vm_details.png b/doc/install/google_cloud_platform/img/vm_details.png
index 2d230416a4b..85b9ca066c8 100644
--- a/doc/install/google_cloud_platform/img/vm_details.png
+++ b/doc/install/google_cloud_platform/img/vm_details.png
Binary files differ
diff --git a/doc/install/installation.md b/doc/install/installation.md
index a310f12b29e..2d657163721 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -457,11 +457,35 @@ GitLab-Pages uses [GNU Make](https://www.gnu.org/software/make/). This step is o
sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_PAGES_VERSION)
sudo -u git -H make
+### Install Gitaly
+
+ # Fetch Gitaly source with Git and compile with Go
+ sudo -u git -H bundle exec rake "gitlab:gitaly:install[/home/git/gitaly]" RAILS_ENV=production
+
+You can specify a different Git repository by providing it as an extra parameter:
+
+ sudo -u git -H bundle exec rake "gitlab:gitaly:install[/home/git/gitaly,https://example.com/gitaly.git]" RAILS_ENV=production
+
+Next, make sure gitaly configured:
+
+ # Restrict Gitaly socket access
+ sudo chmod 0700 /home/git/gitlab/tmp/sockets/private
+ sudo chown git /home/git/gitlab/tmp/sockets/private
+
+ # If you are using non-default settings you need to update config.toml
+ cd /home/git/gitaly
+ sudo -u git -H editor config.toml
+
+For more information about configuring Gitaly see
+[doc/administration/gitaly](../administration/gitaly).
+
### Initialize Database and Activate Advanced Features
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
-
# Type 'yes' to create the database tables.
+
+ # or you can skip the question by adding force=yes
+ sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production force=yes
# When done you see 'Administrator account created:'
@@ -491,28 +515,6 @@ Make GitLab start on boot:
sudo update-rc.d gitlab defaults 21
-### Install Gitaly
-
- # Fetch Gitaly source with Git and compile with Go
- sudo -u git -H bundle exec rake "gitlab:gitaly:install[/home/git/gitaly,/home/git/repositories]" RAILS_ENV=production
-
-You can specify a different Git repository by providing it as an extra parameter:
-
- sudo -u git -H bundle exec rake "gitlab:gitaly:install[/home/git/gitaly,/home/git/repositories,https://example.com/gitaly.git]" RAILS_ENV=production
-
-Next, make sure gitaly configured:
-
- # Restrict Gitaly socket access
- sudo chmod 0700 /home/git/gitlab/tmp/sockets/private
- sudo chown git /home/git/gitlab/tmp/sockets/private
-
- # If you are using non-default settings you need to update config.toml
- cd /home/git/gitaly
- sudo -u git -H editor config.toml
-
-For more information about configuring Gitaly see
-[doc/administration/gitaly](../administration/gitaly).
-
### Setup Logrotate
sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md
index 4e636ae3399..5a6f26319c7 100644
--- a/doc/install/kubernetes/gitlab_chart.md
+++ b/doc/install/kubernetes/gitlab_chart.md
@@ -30,7 +30,7 @@ The `gitlab` chart includes all required dependencies, and takes a few minutes
to deploy.
TIP: **Tip:**
-For large scale deployments, we strongly recommend using the
+For production deployments, we strongly recommend using the
[detailed installation instructions](https://gitlab.com/charts/gitlab/blob/master/doc/installation/README.md)
utilizing [external Postgres, Redis, and object storage](https://gitlab.com/charts/gitlab/tree/master/doc/advanced) services.
diff --git a/doc/install/openshift_and_gitlab/img/add-gitlab-to-project.png b/doc/install/openshift_and_gitlab/img/add-gitlab-to-project.png
index fcad4e59ae3..5b6059dd022 100644
--- a/doc/install/openshift_and_gitlab/img/add-gitlab-to-project.png
+++ b/doc/install/openshift_and_gitlab/img/add-gitlab-to-project.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/add-to-project.png b/doc/install/openshift_and_gitlab/img/add-to-project.png
index bd915a229f6..f9b00431d00 100644
--- a/doc/install/openshift_and_gitlab/img/add-to-project.png
+++ b/doc/install/openshift_and_gitlab/img/add-to-project.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/create-project-ui.png b/doc/install/openshift_and_gitlab/img/create-project-ui.png
index e72866f252a..43b151264c5 100644
--- a/doc/install/openshift_and_gitlab/img/create-project-ui.png
+++ b/doc/install/openshift_and_gitlab/img/create-project-ui.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/gitlab-logs.png b/doc/install/openshift_and_gitlab/img/gitlab-logs.png
index 1e24080c7df..8b90b2f74ac 100644
--- a/doc/install/openshift_and_gitlab/img/gitlab-logs.png
+++ b/doc/install/openshift_and_gitlab/img/gitlab-logs.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/gitlab-overview.png b/doc/install/openshift_and_gitlab/img/gitlab-overview.png
index 3c5df0ea101..3a7bec7c2bc 100644
--- a/doc/install/openshift_and_gitlab/img/gitlab-overview.png
+++ b/doc/install/openshift_and_gitlab/img/gitlab-overview.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/gitlab-running.png b/doc/install/openshift_and_gitlab/img/gitlab-running.png
index c7db691cb30..0fcd9f00d08 100644
--- a/doc/install/openshift_and_gitlab/img/gitlab-running.png
+++ b/doc/install/openshift_and_gitlab/img/gitlab-running.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/gitlab-scale.png b/doc/install/openshift_and_gitlab/img/gitlab-scale.png
index 4903c7d7498..ebae8b588b1 100644
--- a/doc/install/openshift_and_gitlab/img/gitlab-scale.png
+++ b/doc/install/openshift_and_gitlab/img/gitlab-scale.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/gitlab-settings.png b/doc/install/openshift_and_gitlab/img/gitlab-settings.png
index db4360ffef0..0dd1e1f5b8e 100644
--- a/doc/install/openshift_and_gitlab/img/gitlab-settings.png
+++ b/doc/install/openshift_and_gitlab/img/gitlab-settings.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/no-resources.png b/doc/install/openshift_and_gitlab/img/no-resources.png
index 480fb766468..1ef0a0b31e5 100644
--- a/doc/install/openshift_and_gitlab/img/no-resources.png
+++ b/doc/install/openshift_and_gitlab/img/no-resources.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/openshift-infra-project.png b/doc/install/openshift_and_gitlab/img/openshift-infra-project.png
index 8b9f85aa341..e31dda1461c 100644
--- a/doc/install/openshift_and_gitlab/img/openshift-infra-project.png
+++ b/doc/install/openshift_and_gitlab/img/openshift-infra-project.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/pods-overview.png b/doc/install/openshift_and_gitlab/img/pods-overview.png
index e1cf08bd217..65927f65f4f 100644
--- a/doc/install/openshift_and_gitlab/img/pods-overview.png
+++ b/doc/install/openshift_and_gitlab/img/pods-overview.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/rc-name.png b/doc/install/openshift_and_gitlab/img/rc-name.png
index 889e34adbec..16d967b8460 100644
--- a/doc/install/openshift_and_gitlab/img/rc-name.png
+++ b/doc/install/openshift_and_gitlab/img/rc-name.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/running-pods.png b/doc/install/openshift_and_gitlab/img/running-pods.png
index 3fd4e56662f..e08487c881c 100644
--- a/doc/install/openshift_and_gitlab/img/running-pods.png
+++ b/doc/install/openshift_and_gitlab/img/running-pods.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/storage-volumes.png b/doc/install/openshift_and_gitlab/img/storage-volumes.png
index ae1e5381faa..3fd092919bb 100644
--- a/doc/install/openshift_and_gitlab/img/storage-volumes.png
+++ b/doc/install/openshift_and_gitlab/img/storage-volumes.png
Binary files differ
diff --git a/doc/install/openshift_and_gitlab/img/web-console.png b/doc/install/openshift_and_gitlab/img/web-console.png
index aa1425d4f94..012d7703c73 100644
--- a/doc/install/openshift_and_gitlab/img/web-console.png
+++ b/doc/install/openshift_and_gitlab/img/web-console.png
Binary files differ
diff --git a/doc/integration/img/bitbucket_oauth_keys.png b/doc/integration/img/bitbucket_oauth_keys.png
index 6dd2c7d744e..2f0c0eff784 100644
--- a/doc/integration/img/bitbucket_oauth_keys.png
+++ b/doc/integration/img/bitbucket_oauth_keys.png
Binary files differ
diff --git a/doc/integration/img/enable_trello_powerup.png b/doc/integration/img/enable_trello_powerup.png
index 65d01f1c38c..f80d0eadc0b 100644
--- a/doc/integration/img/enable_trello_powerup.png
+++ b/doc/integration/img/enable_trello_powerup.png
Binary files differ
diff --git a/doc/integration/img/enabled-oauth-sign-in-sources.png b/doc/integration/img/enabled-oauth-sign-in-sources.png
index f145aeae75c..e83f9d5cfdf 100644
--- a/doc/integration/img/enabled-oauth-sign-in-sources.png
+++ b/doc/integration/img/enabled-oauth-sign-in-sources.png
Binary files differ
diff --git a/doc/integration/img/facebook_api_keys.png b/doc/integration/img/facebook_api_keys.png
index 9463ec1e7a3..7480b144091 100644
--- a/doc/integration/img/facebook_api_keys.png
+++ b/doc/integration/img/facebook_api_keys.png
Binary files differ
diff --git a/doc/integration/img/facebook_website_url.png b/doc/integration/img/facebook_website_url.png
index 67d78d13951..7873c9905f1 100644
--- a/doc/integration/img/facebook_website_url.png
+++ b/doc/integration/img/facebook_website_url.png
Binary files differ
diff --git a/doc/integration/img/gitlab_app.png b/doc/integration/img/gitlab_app.png
index 8d6a4456fc4..228e8a01305 100644
--- a/doc/integration/img/gitlab_app.png
+++ b/doc/integration/img/gitlab_app.png
Binary files differ
diff --git a/doc/integration/img/google_app.png b/doc/integration/img/google_app.png
index 9fda06dabb1..08f230452b4 100644
--- a/doc/integration/img/google_app.png
+++ b/doc/integration/img/google_app.png
Binary files differ
diff --git a/doc/integration/img/oauth_provider_admin_application.png b/doc/integration/img/oauth_provider_admin_application.png
index c8ecce129c8..353114fea30 100644
--- a/doc/integration/img/oauth_provider_admin_application.png
+++ b/doc/integration/img/oauth_provider_admin_application.png
Binary files differ
diff --git a/doc/integration/img/oauth_provider_application_form.png b/doc/integration/img/oauth_provider_application_form.png
index 954681e054e..c4546d8b3f5 100644
--- a/doc/integration/img/oauth_provider_application_form.png
+++ b/doc/integration/img/oauth_provider_application_form.png
Binary files differ
diff --git a/doc/integration/img/oauth_provider_application_id_secret.png b/doc/integration/img/oauth_provider_application_id_secret.png
index 65cca5f1e1b..21e442b5d04 100644
--- a/doc/integration/img/oauth_provider_application_id_secret.png
+++ b/doc/integration/img/oauth_provider_application_id_secret.png
Binary files differ
diff --git a/doc/integration/img/oauth_provider_authorized_application.png b/doc/integration/img/oauth_provider_authorized_application.png
index ed99db3476d..ebff8529b4e 100644
--- a/doc/integration/img/oauth_provider_authorized_application.png
+++ b/doc/integration/img/oauth_provider_authorized_application.png
Binary files differ
diff --git a/doc/integration/img/submit_issue.png b/doc/integration/img/submit_issue.png
index 8accb78faf3..e794eac189e 100644
--- a/doc/integration/img/submit_issue.png
+++ b/doc/integration/img/submit_issue.png
Binary files differ
diff --git a/doc/integration/img/twitter_app_api_keys.png b/doc/integration/img/twitter_app_api_keys.png
index 34e3c3ba001..c6a3245b1b1 100644
--- a/doc/integration/img/twitter_app_api_keys.png
+++ b/doc/integration/img/twitter_app_api_keys.png
Binary files differ
diff --git a/doc/monitoring/performance/img/grafana_dashboard_import.png b/doc/monitoring/performance/img/grafana_dashboard_import.png
index 7761ea00522..fd639ee0eb8 100644
--- a/doc/monitoring/performance/img/grafana_dashboard_import.png
+++ b/doc/monitoring/performance/img/grafana_dashboard_import.png
Binary files differ
diff --git a/doc/monitoring/performance/img/grafana_data_source_configuration.png b/doc/monitoring/performance/img/grafana_data_source_configuration.png
index 3e749eb8f9d..a98e0ed1e7d 100644
--- a/doc/monitoring/performance/img/grafana_data_source_configuration.png
+++ b/doc/monitoring/performance/img/grafana_data_source_configuration.png
Binary files differ
diff --git a/doc/monitoring/performance/img/grafana_data_source_empty.png b/doc/monitoring/performance/img/grafana_data_source_empty.png
index 33fcaaaef64..549ada8343e 100644
--- a/doc/monitoring/performance/img/grafana_data_source_empty.png
+++ b/doc/monitoring/performance/img/grafana_data_source_empty.png
Binary files differ
diff --git a/doc/monitoring/performance/img/grafana_save_icon.png b/doc/monitoring/performance/img/grafana_save_icon.png
index c18f2147e9d..68a071f5ae2 100644
--- a/doc/monitoring/performance/img/grafana_save_icon.png
+++ b/doc/monitoring/performance/img/grafana_save_icon.png
Binary files differ
diff --git a/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png
index d96a18ebc04..b9563a00e97 100644
--- a/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png
+++ b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png
Binary files differ
diff --git a/doc/public_access/img/restrict_visibility_levels.png b/doc/public_access/img/restrict_visibility_levels.png
index c7d4d87981f..e9315cfb701 100644
--- a/doc/public_access/img/restrict_visibility_levels.png
+++ b/doc/public_access/img/restrict_visibility_levels.png
Binary files differ
diff --git a/doc/raketasks/backup_hrz.png b/doc/raketasks/backup_hrz.png
index c9595b236ee..32690b2904c 100644
--- a/doc/raketasks/backup_hrz.png
+++ b/doc/raketasks/backup_hrz.png
Binary files differ
diff --git a/doc/security/img/outbound_requests_section.png b/doc/security/img/outbound_requests_section.png
index 95c9c6ee771..f7783f34cdd 100644
--- a/doc/security/img/outbound_requests_section.png
+++ b/doc/security/img/outbound_requests_section.png
Binary files differ
diff --git a/doc/security/img/ssh_keys_restrictions_settings.png b/doc/security/img/ssh_keys_restrictions_settings.png
index 2e918fd4b3f..94258af3bf9 100644
--- a/doc/security/img/ssh_keys_restrictions_settings.png
+++ b/doc/security/img/ssh_keys_restrictions_settings.png
Binary files differ
diff --git a/doc/security/img/two_factor_authentication_group_settings.png b/doc/security/img/two_factor_authentication_group_settings.png
index a1b3c58bfdc..05d95554fd9 100644
--- a/doc/security/img/two_factor_authentication_group_settings.png
+++ b/doc/security/img/two_factor_authentication_group_settings.png
Binary files differ
diff --git a/doc/security/img/two_factor_authentication_settings.png b/doc/security/img/two_factor_authentication_settings.png
index 6d89be1eb04..2a2208f98bd 100644
--- a/doc/security/img/two_factor_authentication_settings.png
+++ b/doc/security/img/two_factor_authentication_settings.png
Binary files differ
diff --git a/doc/topics/autodevops/img/guide_environments.png b/doc/topics/autodevops/img/guide_environments.png
index 1d8d5614e64..404db17c57a 100644
--- a/doc/topics/autodevops/img/guide_environments.png
+++ b/doc/topics/autodevops/img/guide_environments.png
Binary files differ
diff --git a/doc/topics/autodevops/img/guide_ide_commit.png b/doc/topics/autodevops/img/guide_ide_commit.png
index 188f60f2a4b..d7be66f4049 100644
--- a/doc/topics/autodevops/img/guide_ide_commit.png
+++ b/doc/topics/autodevops/img/guide_ide_commit.png
Binary files differ
diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/img/branching.png b/doc/topics/git/numerous_undo_possibilities_in_git/img/branching.png
index 9a80c211c99..d8dc9fc8097 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/img/branching.png
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/img/branching.png
Binary files differ
diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/img/rebase_reset.png b/doc/topics/git/numerous_undo_possibilities_in_git/img/rebase_reset.png
index ac7ea9ecddc..6506de209f4 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/img/rebase_reset.png
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/img/rebase_reset.png
Binary files differ
diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/img/revert.png b/doc/topics/git/numerous_undo_possibilities_in_git/img/revert.png
index 13b3a35ca45..040f8118d72 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/img/revert.png
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/img/revert.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/auto-scaling-det.png b/doc/university/high-availability/aws/img/auto-scaling-det.png
index 1e125f301bc..cf32c024bf8 100644
--- a/doc/university/high-availability/aws/img/auto-scaling-det.png
+++ b/doc/university/high-availability/aws/img/auto-scaling-det.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/db-subnet-group.png b/doc/university/high-availability/aws/img/db-subnet-group.png
index 590a02b8dbe..875184af310 100644
--- a/doc/university/high-availability/aws/img/db-subnet-group.png
+++ b/doc/university/high-availability/aws/img/db-subnet-group.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/ig.png b/doc/university/high-availability/aws/img/ig.png
index d4fc2d12de8..2798d4beac3 100644
--- a/doc/university/high-availability/aws/img/ig.png
+++ b/doc/university/high-availability/aws/img/ig.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/instance_specs.png b/doc/university/high-availability/aws/img/instance_specs.png
index 650f375ab3c..2a2b80103fb 100644
--- a/doc/university/high-availability/aws/img/instance_specs.png
+++ b/doc/university/high-availability/aws/img/instance_specs.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/new_vpc.png b/doc/university/high-availability/aws/img/new_vpc.png
index e51c066cee2..d872554fab7 100644
--- a/doc/university/high-availability/aws/img/new_vpc.png
+++ b/doc/university/high-availability/aws/img/new_vpc.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/policies.png b/doc/university/high-availability/aws/img/policies.png
index afcd9e4af9b..e99497a52a2 100644
--- a/doc/university/high-availability/aws/img/policies.png
+++ b/doc/university/high-availability/aws/img/policies.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/rds-net-opt.png b/doc/university/high-availability/aws/img/rds-net-opt.png
index 651cc23b1ab..13130ac96b8 100644
--- a/doc/university/high-availability/aws/img/rds-net-opt.png
+++ b/doc/university/high-availability/aws/img/rds-net-opt.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/rds-sec-group.png b/doc/university/high-availability/aws/img/rds-sec-group.png
index c6d1bc350e4..a88caba62c2 100644
--- a/doc/university/high-availability/aws/img/rds-sec-group.png
+++ b/doc/university/high-availability/aws/img/rds-sec-group.png
Binary files differ
diff --git a/doc/university/high-availability/aws/img/subnet.png b/doc/university/high-availability/aws/img/subnet.png
index de910edc948..681c29bf07a 100644
--- a/doc/university/high-availability/aws/img/subnet.png
+++ b/doc/university/high-availability/aws/img/subnet.png
Binary files differ
diff --git a/doc/university/training/gitlab_flow/production_branch.png b/doc/university/training/gitlab_flow/production_branch.png
index 66456cc51af..956761d7eb8 100644
--- a/doc/university/training/gitlab_flow/production_branch.png
+++ b/doc/university/training/gitlab_flow/production_branch.png
Binary files differ
diff --git a/doc/university/training/gitlab_flow/release_branches.png b/doc/university/training/gitlab_flow/release_branches.png
index 5661e36c4e2..dcb5f97dff0 100644
--- a/doc/university/training/gitlab_flow/release_branches.png
+++ b/doc/university/training/gitlab_flow/release_branches.png
Binary files differ
diff --git a/doc/update/10.7-to-10.8.md b/doc/update/10.7-to-10.8.md
index 13101a987f4..7bb628f9740 100644
--- a/doc/update/10.7-to-10.8.md
+++ b/doc/update/10.7-to-10.8.md
@@ -38,16 +38,16 @@ You can check which version you are running with `ruby -v`.
Download Ruby and compile it:
- ```bash
- mkdir /tmp/ruby && cd /tmp/ruby
- curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.7.tar.gz
- echo '540996fec64984ab6099e34d2f5820b14904f15a ruby-2.3.7.tar.gz' | shasum -c - && tar xzf ruby-2.3.7.tar.gz
- cd ruby-2.3.7
-
- ./configure --disable-install-rdoc
- make
- sudo make install
- ```
+```bash
+mkdir /tmp/ruby && cd /tmp/ruby
+curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.7.tar.gz
+echo '540996fec64984ab6099e34d2f5820b14904f15a ruby-2.3.7.tar.gz' | shasum -c - && tar xzf ruby-2.3.7.tar.gz
+cd ruby-2.3.7
+
+./configure --disable-install-rdoc
+make
+sudo make install
+```
Install Bundler:
diff --git a/doc/user/admin_area/monitoring/img/health_check_token.png b/doc/user/admin_area/monitoring/img/health_check_token.png
index 182549fc484..8d4cf710176 100644
--- a/doc/user/admin_area/monitoring/img/health_check_token.png
+++ b/doc/user/admin_area/monitoring/img/health_check_token.png
Binary files differ
diff --git a/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png b/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png
index 50a86ede56b..723be23e77b 100644
--- a/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png
+++ b/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png
Binary files differ
diff --git a/doc/user/admin_area/settings/img/admin_area_maximum_artifacts_size.png b/doc/user/admin_area/settings/img/admin_area_maximum_artifacts_size.png
index 33fd29e2039..3f827f1f7a3 100644
--- a/doc/user/admin_area/settings/img/admin_area_maximum_artifacts_size.png
+++ b/doc/user/admin_area/settings/img/admin_area_maximum_artifacts_size.png
Binary files differ
diff --git a/doc/user/admin_area/settings/img/domain_blacklist.png b/doc/user/admin_area/settings/img/domain_blacklist.png
index dedd3be1e8f..a7e972b7c0a 100644
--- a/doc/user/admin_area/settings/img/domain_blacklist.png
+++ b/doc/user/admin_area/settings/img/domain_blacklist.png
Binary files differ
diff --git a/doc/user/admin_area/settings/img/restricted_url.png b/doc/user/admin_area/settings/img/restricted_url.png
index 67abd13f741..c71abf0a226 100644
--- a/doc/user/admin_area/settings/img/restricted_url.png
+++ b/doc/user/admin_area/settings/img/restricted_url.png
Binary files differ
diff --git a/doc/user/admin_area/settings/img/update-available.png b/doc/user/admin_area/settings/img/update-available.png
index 0dafdad618e..9887e06c7dc 100644
--- a/doc/user/admin_area/settings/img/update-available.png
+++ b/doc/user/admin_area/settings/img/update-available.png
Binary files differ
diff --git a/doc/user/discussions/img/automatically_resolve_outdated_discussions.png b/doc/user/discussions/img/automatically_resolve_outdated_discussions.png
index 9a798ddd178..ba129e7a618 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
index b15447ec290..3306bf2e60e 100644
--- a/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
+++ b/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
Binary files differ
diff --git a/doc/user/discussions/img/discussion_comment.png b/doc/user/discussions/img/discussion_comment.png
index 8f66d138922..206ddebf54b 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_lock_system_notes.png b/doc/user/discussions/img/discussion_lock_system_notes.png
index 8e8e8e0bc3d..44a47e3f097 100644
--- a/doc/user/discussions/img/discussion_lock_system_notes.png
+++ b/doc/user/discussions/img/discussion_lock_system_notes.png
Binary files differ
diff --git a/doc/user/discussions/img/discussion_view.png b/doc/user/discussions/img/discussion_view.png
index 2ee1db2eab3..3a2b766ed7e 100644
--- a/doc/user/discussions/img/discussion_view.png
+++ b/doc/user/discussions/img/discussion_view.png
Binary files differ
diff --git a/doc/user/discussions/img/lock_form_member.png b/doc/user/discussions/img/lock_form_member.png
index 01c6308d24c..7bfcb4faae6 100644
--- a/doc/user/discussions/img/lock_form_member.png
+++ b/doc/user/discussions/img/lock_form_member.png
Binary files differ
diff --git a/doc/user/discussions/img/lock_form_non_member.png b/doc/user/discussions/img/lock_form_non_member.png
index 3bb70b69580..59e5fd89499 100644
--- a/doc/user/discussions/img/lock_form_non_member.png
+++ b/doc/user/discussions/img/lock_form_non_member.png
Binary files differ
diff --git a/doc/user/discussions/img/new_issue_for_discussion.png b/doc/user/discussions/img/new_issue_for_discussion.png
index 93c9dad8921..819d872a9a2 100644
--- a/doc/user/discussions/img/new_issue_for_discussion.png
+++ b/doc/user/discussions/img/new_issue_for_discussion.png
Binary files differ
diff --git a/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
index bcdc0250d7c..9044926b0eb 100644
--- a/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
+++ b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
Binary files differ
diff --git a/doc/user/discussions/img/preview_issue_for_discussion.png b/doc/user/discussions/img/preview_issue_for_discussion.png
index 2ee0653b2ba..30c273ca4c5 100644
--- a/doc/user/discussions/img/preview_issue_for_discussion.png
+++ b/doc/user/discussions/img/preview_issue_for_discussion.png
Binary files differ
diff --git a/doc/user/discussions/img/preview_issue_for_discussions.png b/doc/user/discussions/img/preview_issue_for_discussions.png
index 3fe0a666678..3d906e1b0b0 100644
--- a/doc/user/discussions/img/preview_issue_for_discussions.png
+++ b/doc/user/discussions/img/preview_issue_for_discussions.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 70340108874..7c19fac31a2 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_discussion_issue_notice.png b/doc/user/discussions/img/resolve_discussion_issue_notice.png
index e0ee6a39ffd..ed50dc1de91 100644
--- a/doc/user/discussions/img/resolve_discussion_issue_notice.png
+++ b/doc/user/discussions/img/resolve_discussion_issue_notice.png
Binary files differ
diff --git a/doc/user/discussions/img/resolve_discussion_open_issue.png b/doc/user/discussions/img/resolve_discussion_open_issue.png
index 98d63278326..9d0a14671d6 100644
--- a/doc/user/discussions/img/resolve_discussion_open_issue.png
+++ b/doc/user/discussions/img/resolve_discussion_open_issue.png
Binary files differ
diff --git a/doc/user/discussions/img/turn_off_lock.png b/doc/user/discussions/img/turn_off_lock.png
index dd05b398a8b..aae1def6f72 100644
--- a/doc/user/discussions/img/turn_off_lock.png
+++ b/doc/user/discussions/img/turn_off_lock.png
Binary files differ
diff --git a/doc/user/discussions/img/turn_on_lock.png b/doc/user/discussions/img/turn_on_lock.png
index 9597da4e14d..f36ffc8831b 100644
--- a/doc/user/discussions/img/turn_on_lock.png
+++ b/doc/user/discussions/img/turn_on_lock.png
Binary files differ
diff --git a/doc/user/group/img/add_new_members.png b/doc/user/group/img/add_new_members.png
index 53f5596de23..99b8e52ea13 100644
--- a/doc/user/group/img/add_new_members.png
+++ b/doc/user/group/img/add_new_members.png
Binary files differ
diff --git a/doc/user/group/img/create_new_group_info.png b/doc/user/group/img/create_new_group_info.png
index 8d2501d9f7a..1ac26fb08d9 100644
--- a/doc/user/group/img/create_new_group_info.png
+++ b/doc/user/group/img/create_new_group_info.png
Binary files differ
diff --git a/doc/user/group/img/create_new_project_from_group.png b/doc/user/group/img/create_new_project_from_group.png
index c35234660db..553cd0759aa 100644
--- a/doc/user/group/img/create_new_project_from_group.png
+++ b/doc/user/group/img/create_new_project_from_group.png
Binary files differ
diff --git a/doc/user/group/img/group_settings.png b/doc/user/group/img/group_settings.png
index 629cd0729aa..1705bf4ce8e 100644
--- a/doc/user/group/img/group_settings.png
+++ b/doc/user/group/img/group_settings.png
Binary files differ
diff --git a/doc/user/group/img/groups.png b/doc/user/group/img/groups.png
index 3173ddce7ff..efdfd5f82cd 100644
--- a/doc/user/group/img/groups.png
+++ b/doc/user/group/img/groups.png
Binary files differ
diff --git a/doc/user/group/img/membership_lock.png b/doc/user/group/img/membership_lock.png
index d31fbb43375..c9ad82c90f2 100644
--- a/doc/user/group/img/membership_lock.png
+++ b/doc/user/group/img/membership_lock.png
Binary files differ
diff --git a/doc/user/group/img/new_group_form.png b/doc/user/group/img/new_group_form.png
index 91727ab5336..1c4d3ec6ceb 100644
--- a/doc/user/group/img/new_group_form.png
+++ b/doc/user/group/img/new_group_form.png
Binary files differ
diff --git a/doc/user/group/img/new_group_from_groups.png b/doc/user/group/img/new_group_from_groups.png
index 9c5dd7ebd8b..ffafac1b1cd 100644
--- a/doc/user/group/img/new_group_from_groups.png
+++ b/doc/user/group/img/new_group_from_groups.png
Binary files differ
diff --git a/doc/user/group/img/new_group_from_other_pages.png b/doc/user/group/img/new_group_from_other_pages.png
index 77427224447..f84501d1ff2 100644
--- a/doc/user/group/img/new_group_from_other_pages.png
+++ b/doc/user/group/img/new_group_from_other_pages.png
Binary files differ
diff --git a/doc/user/group/img/request_access_button.png b/doc/user/group/img/request_access_button.png
index f1aae6afed7..54b490a3bb2 100644
--- a/doc/user/group/img/request_access_button.png
+++ b/doc/user/group/img/request_access_button.png
Binary files differ
diff --git a/doc/user/group/img/select_group_dropdown.png b/doc/user/group/img/select_group_dropdown.png
index 68fc950304c..79eca5d94d5 100644
--- a/doc/user/group/img/select_group_dropdown.png
+++ b/doc/user/group/img/select_group_dropdown.png
Binary files differ
diff --git a/doc/user/group/img/share_with_group_lock.png b/doc/user/group/img/share_with_group_lock.png
index c0f25389eaf..77b00d8a248 100644
--- a/doc/user/group/img/share_with_group_lock.png
+++ b/doc/user/group/img/share_with_group_lock.png
Binary files differ
diff --git a/doc/user/group/img/withdraw_access_request_button.png b/doc/user/group/img/withdraw_access_request_button.png
index c5d8ef6c04f..4365f7fa788 100644
--- a/doc/user/group/img/withdraw_access_request_button.png
+++ b/doc/user/group/img/withdraw_access_request_button.png
Binary files differ
diff --git a/doc/user/group/subgroups/img/group_members.png b/doc/user/group/subgroups/img/group_members.png
index b95fe6263bf..830ccafa794 100644
--- a/doc/user/group/subgroups/img/group_members.png
+++ b/doc/user/group/subgroups/img/group_members.png
Binary files differ
diff --git a/doc/user/group/subgroups/img/mention_subgroups.png b/doc/user/group/subgroups/img/mention_subgroups.png
index 8e6bed0111b..ec370add4f9 100644
--- a/doc/user/group/subgroups/img/mention_subgroups.png
+++ b/doc/user/group/subgroups/img/mention_subgroups.png
Binary files differ
diff --git a/doc/user/img/award_emoji_comment_picker.png b/doc/user/img/award_emoji_comment_picker.png
index 3ad1bab3119..07f90c898ed 100644
--- a/doc/user/img/award_emoji_comment_picker.png
+++ b/doc/user/img/award_emoji_comment_picker.png
Binary files differ
diff --git a/doc/user/img/award_emoji_select.png b/doc/user/img/award_emoji_select.png
index 496acb29eec..269282b94b0 100644
--- a/doc/user/img/award_emoji_select.png
+++ b/doc/user/img/award_emoji_select.png
Binary files differ
diff --git a/doc/user/img/award_emoji_votes_sort_options.png b/doc/user/img/award_emoji_votes_sort_options.png
index dd84b7f4f64..dc02d5169e0 100644
--- a/doc/user/img/award_emoji_votes_sort_options.png
+++ b/doc/user/img/award_emoji_votes_sort_options.png
Binary files differ
diff --git a/doc/user/img/markdown_logo.png b/doc/user/img/markdown_logo.png
index bb3faaaec76..5184851b6cf 100644
--- a/doc/user/img/markdown_logo.png
+++ b/doc/user/img/markdown_logo.png
Binary files differ
diff --git a/doc/user/instance_statistics/img/convdev_index.png b/doc/user/instance_statistics/img/convdev_index.png
index 191295c918b..bee1317438d 100644
--- a/doc/user/instance_statistics/img/convdev_index.png
+++ b/doc/user/instance_statistics/img/convdev_index.png
Binary files differ
diff --git a/doc/user/profile/img/active_sessions_list.png b/doc/user/profile/img/active_sessions_list.png
index 76a52220bcd..5d94dca69cc 100644
--- a/doc/user/profile/img/active_sessions_list.png
+++ b/doc/user/profile/img/active_sessions_list.png
Binary files differ
diff --git a/doc/user/profile/img/personal_access_tokens.png b/doc/user/profile/img/personal_access_tokens.png
index 6aa63dbe342..d29f4cb0a20 100644
--- a/doc/user/profile/img/personal_access_tokens.png
+++ b/doc/user/profile/img/personal_access_tokens.png
Binary files differ
diff --git a/doc/user/profile/img/profil-preferences-navigation-theme.png b/doc/user/profile/img/profil-preferences-navigation-theme.png
index 7adaec33b60..335a19ac290 100644
--- a/doc/user/profile/img/profil-preferences-navigation-theme.png
+++ b/doc/user/profile/img/profil-preferences-navigation-theme.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/add_cluster.png b/doc/user/project/clusters/eks_and_gitlab/img/add_cluster.png
index 9a0559a19d4..94ec83f1514 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/add_cluster.png
+++ b/doc/user/project/clusters/eks_and_gitlab/img/add_cluster.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/create_dns.png b/doc/user/project/clusters/eks_and_gitlab/img/create_dns.png
index 657ab0d9fa9..61ed85e5cd9 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/create_dns.png
+++ b/doc/user/project/clusters/eks_and_gitlab/img/create_dns.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/create_project.png b/doc/user/project/clusters/eks_and_gitlab/img/create_project.png
index f3446131419..b02ab4b9064 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/create_project.png
+++ b/doc/user/project/clusters/eks_and_gitlab/img/create_project.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.png b/doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.png
index d6c3b1b3a94..0d9fcc838d9 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.png
+++ b/doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/environment.png b/doc/user/project/clusters/eks_and_gitlab/img/environment.png
index 77d711ba8f6..4714c447026 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/environment.png
+++ b/doc/user/project/clusters/eks_and_gitlab/img/environment.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/new_project.png b/doc/user/project/clusters/eks_and_gitlab/img/new_project.png
index d401c4ac2bf..02afc099f10 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/new_project.png
+++ b/doc/user/project/clusters/eks_and_gitlab/img/new_project.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/pipeline.png b/doc/user/project/clusters/eks_and_gitlab/img/pipeline.png
index 5f9c9815c24..0eb00d0faa7 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/pipeline.png
+++ b/doc/user/project/clusters/eks_and_gitlab/img/pipeline.png
Binary files differ
diff --git a/doc/user/project/deploy_tokens/img/deploy_tokens.png b/doc/user/project/deploy_tokens/img/deploy_tokens.png
index 7e2d67a3120..55c537fd1d3 100644
--- a/doc/user/project/deploy_tokens/img/deploy_tokens.png
+++ b/doc/user/project/deploy_tokens/img/deploy_tokens.png
Binary files differ
diff --git a/doc/user/project/img/bulk-editing.png b/doc/user/project/img/bulk-editing.png
index f6b163f55d9..8ae649e5020 100644
--- a/doc/user/project/img/bulk-editing.png
+++ b/doc/user/project/img/bulk-editing.png
Binary files differ
diff --git a/doc/user/project/img/cycle_analytics_landing_page.png b/doc/user/project/img/cycle_analytics_landing_page.png
index 316612c0da0..8b17fae5e05 100644
--- a/doc/user/project/img/cycle_analytics_landing_page.png
+++ b/doc/user/project/img/cycle_analytics_landing_page.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_assignee_lists.png b/doc/user/project/img/issue_board_assignee_lists.png
index 1ec94d22e33..f2660cd8f80 100644
--- a/doc/user/project/img/issue_board_assignee_lists.png
+++ b/doc/user/project/img/issue_board_assignee_lists.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_creation.png b/doc/user/project/img/issue_board_creation.png
index 9dc4925b0a5..099fe6eee21 100644
--- a/doc/user/project/img/issue_board_creation.png
+++ b/doc/user/project/img/issue_board_creation.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_edit_button.png b/doc/user/project/img/issue_board_edit_button.png
index 23883175344..a0dc6f41592 100644
--- a/doc/user/project/img/issue_board_edit_button.png
+++ b/doc/user/project/img/issue_board_edit_button.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_move_issue_card_list.png b/doc/user/project/img/issue_board_move_issue_card_list.png
index cce252234c1..13750a63766 100644
--- a/doc/user/project/img/issue_board_move_issue_card_list.png
+++ b/doc/user/project/img/issue_board_move_issue_card_list.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_view_scope.png b/doc/user/project/img/issue_board_view_scope.png
index 4e03cecbc2d..d173679a0e7 100644
--- a/doc/user/project/img/issue_board_view_scope.png
+++ b/doc/user/project/img/issue_board_view_scope.png
Binary files differ
diff --git a/doc/user/project/img/issue_boards_add_issues_modal.png b/doc/user/project/img/issue_boards_add_issues_modal.png
index 625a4304eaf..ecddf6709d0 100644
--- a/doc/user/project/img/issue_boards_add_issues_modal.png
+++ b/doc/user/project/img/issue_boards_add_issues_modal.png
Binary files differ
diff --git a/doc/user/project/img/issue_boards_multiple.png b/doc/user/project/img/issue_boards_multiple.png
index 4b2b8d457f1..7bb088aad0b 100644
--- a/doc/user/project/img/issue_boards_multiple.png
+++ b/doc/user/project/img/issue_boards_multiple.png
Binary files differ
diff --git a/doc/user/project/img/issue_boards_remove_issue.png b/doc/user/project/img/issue_boards_remove_issue.png
index 9a2fad2cc7f..7050e6c3ede 100644
--- a/doc/user/project/img/issue_boards_remove_issue.png
+++ b/doc/user/project/img/issue_boards_remove_issue.png
Binary files differ
diff --git a/doc/user/project/img/koding_build-in-progress.png b/doc/user/project/img/koding_build-in-progress.png
index 79b7b2f10a2..118b97c07e1 100644
--- a/doc/user/project/img/koding_build-in-progress.png
+++ b/doc/user/project/img/koding_build-in-progress.png
Binary files differ
diff --git a/doc/user/project/img/koding_build-success.png b/doc/user/project/img/koding_build-success.png
index a2342cfd324..0f3b954abf5 100644
--- a/doc/user/project/img/koding_build-success.png
+++ b/doc/user/project/img/koding_build-success.png
Binary files differ
diff --git a/doc/user/project/img/koding_commit-koding.yml.png b/doc/user/project/img/koding_commit-koding.yml.png
index 16842410ae2..d921c73dc73 100644
--- a/doc/user/project/img/koding_commit-koding.yml.png
+++ b/doc/user/project/img/koding_commit-koding.yml.png
Binary files differ
diff --git a/doc/user/project/img/koding_edit-on-ide.png b/doc/user/project/img/koding_edit-on-ide.png
index ab861281d3e..25ca7694fe0 100644
--- a/doc/user/project/img/koding_edit-on-ide.png
+++ b/doc/user/project/img/koding_edit-on-ide.png
Binary files differ
diff --git a/doc/user/project/img/koding_enable-koding.png b/doc/user/project/img/koding_enable-koding.png
index 0b6fcfadcc5..7e6c1735df2 100644
--- a/doc/user/project/img/koding_enable-koding.png
+++ b/doc/user/project/img/koding_enable-koding.png
Binary files differ
diff --git a/doc/user/project/img/koding_landing.png b/doc/user/project/img/koding_landing.png
index 1eeddcd3813..ac880376e09 100644
--- a/doc/user/project/img/koding_landing.png
+++ b/doc/user/project/img/koding_landing.png
Binary files differ
diff --git a/doc/user/project/img/koding_run-in-ide.png b/doc/user/project/img/koding_run-in-ide.png
index d22e5023c59..fb5825a4010 100644
--- a/doc/user/project/img/koding_run-in-ide.png
+++ b/doc/user/project/img/koding_run-in-ide.png
Binary files differ
diff --git a/doc/user/project/img/koding_stack-import.png b/doc/user/project/img/koding_stack-import.png
index 245ccb07ba3..483bfad7d6a 100644
--- a/doc/user/project/img/koding_stack-import.png
+++ b/doc/user/project/img/koding_stack-import.png
Binary files differ
diff --git a/doc/user/project/img/koding_start-build.png b/doc/user/project/img/koding_start-build.png
index 3f5c16d5d2f..c09a6d669f0 100644
--- a/doc/user/project/img/koding_start-build.png
+++ b/doc/user/project/img/koding_start-build.png
Binary files differ
diff --git a/doc/user/project/img/labels_generate_default.png b/doc/user/project/img/labels_generate_default.png
index fca2a06e04f..982a4df999c 100644
--- a/doc/user/project/img/labels_generate_default.png
+++ b/doc/user/project/img/labels_generate_default.png
Binary files differ
diff --git a/doc/user/project/img/labels_group_issues.png b/doc/user/project/img/labels_group_issues.png
index 29dcf7ff45e..cea1d304d31 100644
--- a/doc/user/project/img/labels_group_issues.png
+++ b/doc/user/project/img/labels_group_issues.png
Binary files differ
diff --git a/doc/user/project/img/labels_list.png b/doc/user/project/img/labels_list.png
index 12c47ea9766..6878349fc0c 100644
--- a/doc/user/project/img/labels_list.png
+++ b/doc/user/project/img/labels_list.png
Binary files differ
diff --git a/doc/user/project/img/labels_prioritized.png b/doc/user/project/img/labels_prioritized.png
index 57dcfe89b3d..7ce2d08b38c 100644
--- a/doc/user/project/img/labels_prioritized.png
+++ b/doc/user/project/img/labels_prioritized.png
Binary files differ
diff --git a/doc/user/project/img/labels_project_list_search.png b/doc/user/project/img/labels_project_list_search.png
index ff9bf92e1c3..512d7767e6e 100644
--- a/doc/user/project/img/labels_project_list_search.png
+++ b/doc/user/project/img/labels_project_list_search.png
Binary files differ
diff --git a/doc/user/project/img/labels_promotion.png b/doc/user/project/img/labels_promotion.png
index 8a5efd210a2..762a3773692 100644
--- a/doc/user/project/img/labels_promotion.png
+++ b/doc/user/project/img/labels_promotion.png
Binary files differ
diff --git a/doc/user/project/img/labels_sidebar.png b/doc/user/project/img/labels_sidebar.png
index 7349c6d4f0c..454a0ca3f07 100644
--- a/doc/user/project/img/labels_sidebar.png
+++ b/doc/user/project/img/labels_sidebar.png
Binary files differ
diff --git a/doc/user/project/img/labels_sidebar_assign.png b/doc/user/project/img/labels_sidebar_assign.png
index 61e8d04fc85..5b7fb78b032 100644
--- a/doc/user/project/img/labels_sidebar_assign.png
+++ b/doc/user/project/img/labels_sidebar_assign.png
Binary files differ
diff --git a/doc/user/project/img/labels_sidebar_inline.png b/doc/user/project/img/labels_sidebar_inline.png
index 31fa397761d..2186f14ea92 100644
--- a/doc/user/project/img/labels_sidebar_inline.png
+++ b/doc/user/project/img/labels_sidebar_inline.png
Binary files differ
diff --git a/doc/user/project/img/labels_sort_label_priority.png b/doc/user/project/img/labels_sort_label_priority.png
index c8b97639121..faf629ac61d 100644
--- a/doc/user/project/img/labels_sort_label_priority.png
+++ b/doc/user/project/img/labels_sort_label_priority.png
Binary files differ
diff --git a/doc/user/project/img/labels_sort_priority.png b/doc/user/project/img/labels_sort_priority.png
index a95198e7f72..a6b5fca26f4 100644
--- a/doc/user/project/img/labels_sort_priority.png
+++ b/doc/user/project/img/labels_sort_priority.png
Binary files differ
diff --git a/doc/user/project/img/labels_subscriptions.png b/doc/user/project/img/labels_subscriptions.png
index 8bcb3b57f6c..f3c4235d051 100644
--- a/doc/user/project/img/labels_subscriptions.png
+++ b/doc/user/project/img/labels_subscriptions.png
Binary files differ
diff --git a/doc/user/project/img/priority_sort_order.png b/doc/user/project/img/priority_sort_order.png
index c558ec23b0e..cd1dd8237c0 100644
--- a/doc/user/project/img/priority_sort_order.png
+++ b/doc/user/project/img/priority_sort_order.png
Binary files differ
diff --git a/doc/user/project/img/project_overview_badges.png b/doc/user/project/img/project_overview_badges.png
index 3067a7dfa13..83b9766828a 100644
--- a/doc/user/project/img/project_overview_badges.png
+++ b/doc/user/project/img/project_overview_badges.png
Binary files differ
diff --git a/doc/user/project/img/project_repository_settings.png b/doc/user/project/img/project_repository_settings.png
index aa4d4452c87..69d36753a58 100644
--- a/doc/user/project/img/project_repository_settings.png
+++ b/doc/user/project/img/project_repository_settings.png
Binary files differ
diff --git a/doc/user/project/img/protected_branches_delete.png b/doc/user/project/img/protected_branches_delete.png
index cfdfe6c6c29..8910ae9e39d 100644
--- a/doc/user/project/img/protected_branches_delete.png
+++ b/doc/user/project/img/protected_branches_delete.png
Binary files differ
diff --git a/doc/user/project/img/protected_branches_devs_can_push.png b/doc/user/project/img/protected_branches_devs_can_push.png
index 320e6eb7fee..b537839c00b 100644
--- a/doc/user/project/img/protected_branches_devs_can_push.png
+++ b/doc/user/project/img/protected_branches_devs_can_push.png
Binary files differ
diff --git a/doc/user/project/img/protected_branches_error_ui.png b/doc/user/project/img/protected_branches_error_ui.png
index 3f8e462d3ad..62839e49d89 100644
--- a/doc/user/project/img/protected_branches_error_ui.png
+++ b/doc/user/project/img/protected_branches_error_ui.png
Binary files differ
diff --git a/doc/user/project/img/protected_branches_list.png b/doc/user/project/img/protected_branches_list.png
index 1b2936cb711..495ce4d7b6f 100644
--- a/doc/user/project/img/protected_branches_list.png
+++ b/doc/user/project/img/protected_branches_list.png
Binary files differ
diff --git a/doc/user/project/img/protected_branches_page.png b/doc/user/project/img/protected_branches_page.png
index 4e5afff3bae..9b10991f62e 100644
--- a/doc/user/project/img/protected_branches_page.png
+++ b/doc/user/project/img/protected_branches_page.png
Binary files differ
diff --git a/doc/user/project/img/protected_tag_matches.png b/doc/user/project/img/protected_tag_matches.png
index a36a11a1271..e89d0a47073 100644
--- a/doc/user/project/img/protected_tag_matches.png
+++ b/doc/user/project/img/protected_tag_matches.png
Binary files differ
diff --git a/doc/user/project/img/protected_tags_list.png b/doc/user/project/img/protected_tags_list.png
index c5e42dc0705..6c5295e0f4b 100644
--- a/doc/user/project/img/protected_tags_list.png
+++ b/doc/user/project/img/protected_tags_list.png
Binary files differ
diff --git a/doc/user/project/img/protected_tags_page.png b/doc/user/project/img/protected_tags_page.png
index 3848d91ebd6..5f8a2106cd1 100644
--- a/doc/user/project/img/protected_tags_page.png
+++ b/doc/user/project/img/protected_tags_page.png
Binary files differ
diff --git a/doc/user/project/img/protected_tags_permissions_dropdown.png b/doc/user/project/img/protected_tags_permissions_dropdown.png
index 9e0fc4e2a43..77098eeb591 100644
--- a/doc/user/project/img/protected_tags_permissions_dropdown.png
+++ b/doc/user/project/img/protected_tags_permissions_dropdown.png
Binary files differ
diff --git a/doc/user/project/import/img/bitbucket_server_import_credentials.png b/doc/user/project/import/img/bitbucket_server_import_credentials.png
index 70b26e89d49..25bcc3ab6e6 100644
--- a/doc/user/project/import/img/bitbucket_server_import_credentials.png
+++ b/doc/user/project/import/img/bitbucket_server_import_credentials.png
Binary files differ
diff --git a/doc/user/project/import/img/bitbucket_server_import_select_project.png b/doc/user/project/import/img/bitbucket_server_import_select_project.png
index e5b1b89e6a3..e7fddef9955 100644
--- a/doc/user/project/import/img/bitbucket_server_import_select_project.png
+++ b/doc/user/project/import/img/bitbucket_server_import_select_project.png
Binary files differ
diff --git a/doc/user/project/import/img/fogbugz_import_login.png b/doc/user/project/import/img/fogbugz_import_login.png
index 96bce70b74d..6ba4d443f1a 100644
--- a/doc/user/project/import/img/fogbugz_import_login.png
+++ b/doc/user/project/import/img/fogbugz_import_login.png
Binary files differ
diff --git a/doc/user/project/import/img/fogbugz_import_select_fogbogz.png b/doc/user/project/import/img/fogbugz_import_select_fogbogz.png
index b26c652e382..d207646a6f2 100644
--- a/doc/user/project/import/img/fogbugz_import_select_fogbogz.png
+++ b/doc/user/project/import/img/fogbugz_import_select_fogbogz.png
Binary files differ
diff --git a/doc/user/project/import/img/fogbugz_import_select_project.png b/doc/user/project/import/img/fogbugz_import_select_project.png
index ccc82f9d4cd..b5e6f497f9b 100644
--- a/doc/user/project/import/img/fogbugz_import_select_project.png
+++ b/doc/user/project/import/img/fogbugz_import_select_project.png
Binary files differ
diff --git a/doc/user/project/import/img/import_projects_from_gitea_new_import.png b/doc/user/project/import/img/import_projects_from_gitea_new_import.png
index a3f603cbd0a..41eb4b2bd00 100644
--- a/doc/user/project/import/img/import_projects_from_gitea_new_import.png
+++ b/doc/user/project/import/img/import_projects_from_gitea_new_import.png
Binary files differ
diff --git a/doc/user/project/import/img/import_projects_from_github_select_auth_method.png b/doc/user/project/import/img/import_projects_from_github_select_auth_method.png
index 1ccb38a815e..90e6243aec0 100644
--- a/doc/user/project/import/img/import_projects_from_github_select_auth_method.png
+++ b/doc/user/project/import/img/import_projects_from_github_select_auth_method.png
Binary files differ
diff --git a/doc/user/project/import/img/import_projects_from_new_project_page.png b/doc/user/project/import/img/import_projects_from_new_project_page.png
index 40402eae226..7c32d3555d1 100644
--- a/doc/user/project/import/img/import_projects_from_new_project_page.png
+++ b/doc/user/project/import/img/import_projects_from_new_project_page.png
Binary files differ
diff --git a/doc/user/project/integrations/img/hangouts_chat_configuration.png b/doc/user/project/integrations/img/hangouts_chat_configuration.png
index 33fadbe6547..54aaef6632d 100644
--- a/doc/user/project/integrations/img/hangouts_chat_configuration.png
+++ b/doc/user/project/integrations/img/hangouts_chat_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/img/issue_configuration.png b/doc/user/project/integrations/img/issue_configuration.png
index 2049d60fdd2..5dfd85974d8 100644
--- a/doc/user/project/integrations/img/issue_configuration.png
+++ b/doc/user/project/integrations/img/issue_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_group_access.png b/doc/user/project/integrations/img/jira_group_access.png
index 9d64cc57269..448cc55504d 100644
--- a/doc/user/project/integrations/img/jira_group_access.png
+++ b/doc/user/project/integrations/img/jira_group_access.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_project_name.png b/doc/user/project/integrations/img/jira_project_name.png
index 8540a427461..981c7f7ca18 100644
--- a/doc/user/project/integrations/img/jira_project_name.png
+++ b/doc/user/project/integrations/img/jira_project_name.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_project_settings.png b/doc/user/project/integrations/img/jira_project_settings.png
index cb6a6ba14ce..d96002b7db8 100644
--- a/doc/user/project/integrations/img/jira_project_settings.png
+++ b/doc/user/project/integrations/img/jira_project_settings.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_service.png b/doc/user/project/integrations/img/jira_service.png
index 8e073b84ff9..0ae2fa28756 100644
--- a/doc/user/project/integrations/img/jira_service.png
+++ b/doc/user/project/integrations/img/jira_service.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_service_close_comment.png b/doc/user/project/integrations/img/jira_service_close_comment.png
index bb9cd7e3d13..9af0d38f098 100644
--- a/doc/user/project/integrations/img/jira_service_close_comment.png
+++ b/doc/user/project/integrations/img/jira_service_close_comment.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_service_page.png b/doc/user/project/integrations/img/jira_service_page.png
index 63aa0e99a50..c75c11888a8 100644
--- a/doc/user/project/integrations/img/jira_service_page.png
+++ b/doc/user/project/integrations/img/jira_service_page.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_user_management_link.png b/doc/user/project/integrations/img/jira_user_management_link.png
index f81c5b5fc87..5eb9d031c3e 100644
--- a/doc/user/project/integrations/img/jira_user_management_link.png
+++ b/doc/user/project/integrations/img/jira_user_management_link.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_bot_auth.png b/doc/user/project/integrations/img/mattermost_bot_auth.png
index 830b7849f3d..a05d8da1237 100644
--- a/doc/user/project/integrations/img/mattermost_bot_auth.png
+++ b/doc/user/project/integrations/img/mattermost_bot_auth.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_bot_available_commands.png b/doc/user/project/integrations/img/mattermost_bot_available_commands.png
index b51798cf10d..3232ccc3451 100644
--- a/doc/user/project/integrations/img/mattermost_bot_available_commands.png
+++ b/doc/user/project/integrations/img/mattermost_bot_available_commands.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_configuration.png b/doc/user/project/integrations/img/mattermost_configuration.png
index f52acf4ef3b..e0b55b23520 100644
--- a/doc/user/project/integrations/img/mattermost_configuration.png
+++ b/doc/user/project/integrations/img/mattermost_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_console_integrations.png b/doc/user/project/integrations/img/mattermost_console_integrations.png
index 92a30da5be0..625b57d4dc9 100644
--- a/doc/user/project/integrations/img/mattermost_console_integrations.png
+++ b/doc/user/project/integrations/img/mattermost_console_integrations.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_gitlab_token.png b/doc/user/project/integrations/img/mattermost_gitlab_token.png
index 257018914d2..63140503824 100644
--- a/doc/user/project/integrations/img/mattermost_gitlab_token.png
+++ b/doc/user/project/integrations/img/mattermost_gitlab_token.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_goto_console.png b/doc/user/project/integrations/img/mattermost_goto_console.png
index 3354c2a24b4..8bacbe485f4 100644
--- a/doc/user/project/integrations/img/mattermost_goto_console.png
+++ b/doc/user/project/integrations/img/mattermost_goto_console.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_slash_command_configuration.png b/doc/user/project/integrations/img/mattermost_slash_command_configuration.png
index 12766ab2b34..f9e9de439ca 100644
--- a/doc/user/project/integrations/img/mattermost_slash_command_configuration.png
+++ b/doc/user/project/integrations/img/mattermost_slash_command_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/img/mattermost_team_integrations.png b/doc/user/project/integrations/img/mattermost_team_integrations.png
index 69d4a231e5a..c2b68256e11 100644
--- a/doc/user/project/integrations/img/mattermost_team_integrations.png
+++ b/doc/user/project/integrations/img/mattermost_team_integrations.png
Binary files differ
diff --git a/doc/user/project/integrations/img/merge_request_performance.png b/doc/user/project/integrations/img/merge_request_performance.png
index eba6515a6ae..a9cd761cdcb 100644
--- a/doc/user/project/integrations/img/merge_request_performance.png
+++ b/doc/user/project/integrations/img/merge_request_performance.png
Binary files differ
diff --git a/doc/user/project/integrations/img/microsoft_teams_configuration.png b/doc/user/project/integrations/img/microsoft_teams_configuration.png
index b5c9efc3dd9..627715d5c18 100644
--- a/doc/user/project/integrations/img/microsoft_teams_configuration.png
+++ b/doc/user/project/integrations/img/microsoft_teams_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/img/project_services.png b/doc/user/project/integrations/img/project_services.png
index 25b6cd5690b..5fed38a349c 100644
--- a/doc/user/project/integrations/img/project_services.png
+++ b/doc/user/project/integrations/img/project_services.png
Binary files differ
diff --git a/doc/user/project/integrations/img/prometheus_dashboard.png b/doc/user/project/integrations/img/prometheus_dashboard.png
index bd19f1b44cc..1fa36ca2675 100644
--- a/doc/user/project/integrations/img/prometheus_dashboard.png
+++ b/doc/user/project/integrations/img/prometheus_dashboard.png
Binary files differ
diff --git a/doc/user/project/integrations/img/prometheus_deploy.png b/doc/user/project/integrations/img/prometheus_deploy.png
index d39081bcc7b..3f19f23b0cc 100644
--- a/doc/user/project/integrations/img/prometheus_deploy.png
+++ b/doc/user/project/integrations/img/prometheus_deploy.png
Binary files differ
diff --git a/doc/user/project/integrations/img/prometheus_yaml_deploy.png b/doc/user/project/integrations/img/prometheus_yaml_deploy.png
index 978cd7eaa50..78dd178a077 100644
--- a/doc/user/project/integrations/img/prometheus_yaml_deploy.png
+++ b/doc/user/project/integrations/img/prometheus_yaml_deploy.png
Binary files differ
diff --git a/doc/user/project/integrations/img/redmine_configuration.png b/doc/user/project/integrations/img/redmine_configuration.png
index 7b6dd271401..eb392b848b5 100644
--- a/doc/user/project/integrations/img/redmine_configuration.png
+++ b/doc/user/project/integrations/img/redmine_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/img/services_templates_redmine_example.png b/doc/user/project/integrations/img/services_templates_redmine_example.png
index 379cef9888d..34594dfdd55 100644
--- a/doc/user/project/integrations/img/services_templates_redmine_example.png
+++ b/doc/user/project/integrations/img/services_templates_redmine_example.png
Binary files differ
diff --git a/doc/user/project/integrations/img/slack_configuration.png b/doc/user/project/integrations/img/slack_configuration.png
index 527824fc3eb..53b30e0e8cd 100644
--- a/doc/user/project/integrations/img/slack_configuration.png
+++ b/doc/user/project/integrations/img/slack_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/img/webhook_logs.png b/doc/user/project/integrations/img/webhook_logs.png
index 803678db6b6..24bb593c7d0 100644
--- a/doc/user/project/integrations/img/webhook_logs.png
+++ b/doc/user/project/integrations/img/webhook_logs.png
Binary files differ
diff --git a/doc/user/project/integrations/img/webhook_testing.png b/doc/user/project/integrations/img/webhook_testing.png
index 176dcec9d8a..acfebf473b9 100644
--- a/doc/user/project/integrations/img/webhook_testing.png
+++ b/doc/user/project/integrations/img/webhook_testing.png
Binary files differ
diff --git a/doc/user/project/integrations/img/webhooks_ssl.png b/doc/user/project/integrations/img/webhooks_ssl.png
index 21ddec4ebdf..f023e9665f2 100644
--- a/doc/user/project/integrations/img/webhooks_ssl.png
+++ b/doc/user/project/integrations/img/webhooks_ssl.png
Binary files differ
diff --git a/doc/user/project/issues/img/confidential_issues_index_page.png b/doc/user/project/issues/img/confidential_issues_index_page.png
index f3efe0ce04e..16979bf9ac2 100644
--- a/doc/user/project/issues/img/confidential_issues_index_page.png
+++ b/doc/user/project/issues/img/confidential_issues_index_page.png
Binary files differ
diff --git a/doc/user/project/issues/img/delete_issue.png b/doc/user/project/issues/img/delete_issue.png
index a356f52044e..87ea65956fc 100644
--- a/doc/user/project/issues/img/delete_issue.png
+++ b/doc/user/project/issues/img/delete_issue.png
Binary files differ
diff --git a/doc/user/project/issues/img/due_dates_create.png b/doc/user/project/issues/img/due_dates_create.png
index ece35d44213..392fb3553cb 100644
--- a/doc/user/project/issues/img/due_dates_create.png
+++ b/doc/user/project/issues/img/due_dates_create.png
Binary files differ
diff --git a/doc/user/project/issues/img/group_issues_list_view.png b/doc/user/project/issues/img/group_issues_list_view.png
index bba964076d0..c951a9e2dcd 100644
--- a/doc/user/project/issues/img/group_issues_list_view.png
+++ b/doc/user/project/issues/img/group_issues_list_view.png
Binary files differ
diff --git a/doc/user/project/issues/img/issue_board.png b/doc/user/project/issues/img/issue_board.png
index 87b1016cc76..df9d6f64985 100644
--- a/doc/user/project/issues/img/issue_board.png
+++ b/doc/user/project/issues/img/issue_board.png
Binary files differ
diff --git a/doc/user/project/issues/img/issue_template.png b/doc/user/project/issues/img/issue_template.png
index 0e4c8df897b..6cb2c07d27e 100644
--- a/doc/user/project/issues/img/issue_template.png
+++ b/doc/user/project/issues/img/issue_template.png
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue_from_email.png b/doc/user/project/issues/img/new_issue_from_email.png
index 775ea0cdffb..6da899ea37c 100644
--- a/doc/user/project/issues/img/new_issue_from_email.png
+++ b/doc/user/project/issues/img/new_issue_from_email.png
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue_from_issue_board.png b/doc/user/project/issues/img/new_issue_from_issue_board.png
index da892eff0a6..30a1ffb9011 100644
--- a/doc/user/project/issues/img/new_issue_from_issue_board.png
+++ b/doc/user/project/issues/img/new_issue_from_issue_board.png
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png
index 4b9535f6b15..474ca2b45c0 100644
--- a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png
+++ b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png
Binary files differ
diff --git a/doc/user/project/issues/img/project_issues_list_view.png b/doc/user/project/issues/img/project_issues_list_view.png
index 584a81aab8a..c80bd58f5c9 100644
--- a/doc/user/project/issues/img/project_issues_list_view.png
+++ b/doc/user/project/issues/img/project_issues_list_view.png
Binary files differ
diff --git a/doc/user/project/issues/img/sidebar_confidential_issue.png b/doc/user/project/issues/img/sidebar_confidential_issue.png
index d99a1ca756e..a320f4dcfe5 100644
--- a/doc/user/project/issues/img/sidebar_confidential_issue.png
+++ b/doc/user/project/issues/img/sidebar_confidential_issue.png
Binary files differ
diff --git a/doc/user/project/issues/img/sidebar_move_issue.png b/doc/user/project/issues/img/sidebar_move_issue.png
index 1e688cec894..031284a24b2 100644
--- a/doc/user/project/issues/img/sidebar_move_issue.png
+++ b/doc/user/project/issues/img/sidebar_move_issue.png
Binary files differ
diff --git a/doc/user/project/issues/img/sidebar_not_confidential_issue.png b/doc/user/project/issues/img/sidebar_not_confidential_issue.png
index 2e6cbbc5b3a..c09f8204b37 100644
--- a/doc/user/project/issues/img/sidebar_not_confidential_issue.png
+++ b/doc/user/project/issues/img/sidebar_not_confidential_issue.png
Binary files differ
diff --git a/doc/user/project/issues/img/turn_off_confidentiality.png b/doc/user/project/issues/img/turn_off_confidentiality.png
index 248ae6522d6..04a85933071 100644
--- a/doc/user/project/issues/img/turn_off_confidentiality.png
+++ b/doc/user/project/issues/img/turn_off_confidentiality.png
Binary files differ
diff --git a/doc/user/project/issues/img/turn_on_confidentiality.png b/doc/user/project/issues/img/turn_on_confidentiality.png
index fac4c833699..fac360ca6dc 100644
--- a/doc/user/project/issues/img/turn_on_confidentiality.png
+++ b/doc/user/project/issues/img/turn_on_confidentiality.png
Binary files differ
diff --git a/doc/user/project/members/img/access_requests_management.png b/doc/user/project/members/img/access_requests_management.png
index 3693bed869b..8996d9564d7 100644
--- a/doc/user/project/members/img/access_requests_management.png
+++ b/doc/user/project/members/img/access_requests_management.png
Binary files differ
diff --git a/doc/user/project/members/img/add_new_user_to_project_settings.png b/doc/user/project/members/img/add_new_user_to_project_settings.png
index 40db600455f..e49ea1a3e3d 100644
--- a/doc/user/project/members/img/add_new_user_to_project_settings.png
+++ b/doc/user/project/members/img/add_new_user_to_project_settings.png
Binary files differ
diff --git a/doc/user/project/members/img/add_user_email_accept.png b/doc/user/project/members/img/add_user_email_accept.png
index 763b3ff463d..cbee9e08c70 100644
--- a/doc/user/project/members/img/add_user_email_accept.png
+++ b/doc/user/project/members/img/add_user_email_accept.png
Binary files differ
diff --git a/doc/user/project/members/img/add_user_import_members_from_another_project.png b/doc/user/project/members/img/add_user_import_members_from_another_project.png
index 0c32001098e..cb3b70bd4b5 100644
--- a/doc/user/project/members/img/add_user_import_members_from_another_project.png
+++ b/doc/user/project/members/img/add_user_import_members_from_another_project.png
Binary files differ
diff --git a/doc/user/project/members/img/add_user_members_menu.png b/doc/user/project/members/img/add_user_members_menu.png
index 8e61d15fe65..6f08088b52f 100644
--- a/doc/user/project/members/img/add_user_members_menu.png
+++ b/doc/user/project/members/img/add_user_members_menu.png
Binary files differ
diff --git a/doc/user/project/members/img/max_access_level.png b/doc/user/project/members/img/max_access_level.png
index 63f33f9d91d..42a0416ffbb 100644
--- a/doc/user/project/members/img/max_access_level.png
+++ b/doc/user/project/members/img/max_access_level.png
Binary files differ
diff --git a/doc/user/project/members/img/request_access_button.png b/doc/user/project/members/img/request_access_button.png
index 608baccb0ca..e8b490b91b8 100644
--- a/doc/user/project/members/img/request_access_button.png
+++ b/doc/user/project/members/img/request_access_button.png
Binary files differ
diff --git a/doc/user/project/members/img/withdraw_access_request_button.png b/doc/user/project/members/img/withdraw_access_request_button.png
index 6edd786b151..6a3172dfcdb 100644
--- a/doc/user/project/members/img/withdraw_access_request_button.png
+++ b/doc/user/project/members/img/withdraw_access_request_button.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/allow_collaboration.png b/doc/user/project/merge_requests/img/allow_collaboration.png
index 75596e7d9ad..3c81e4c27b8 100644
--- a/doc/user/project/merge_requests/img/allow_collaboration.png
+++ b/doc/user/project/merge_requests/img/allow_collaboration.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png b/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png
index 7dc344f8cf6..c98821548f8 100644
--- a/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png
+++ b/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png b/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png
index 811b0998f85..8b51503419b 100644
--- a/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png
+++ b/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/create_from_email.png b/doc/user/project/merge_requests/img/create_from_email.png
index 71eb4bf267d..610f0b3d0c1 100644
--- a/doc/user/project/merge_requests/img/create_from_email.png
+++ b/doc/user/project/merge_requests/img/create_from_email.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_conflict_editor.png b/doc/user/project/merge_requests/img/merge_conflict_editor.png
index 6660920c191..f10efbce5f5 100644
--- a/doc/user/project/merge_requests/img/merge_conflict_editor.png
+++ b/doc/user/project/merge_requests/img/merge_conflict_editor.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_request.png b/doc/user/project/merge_requests/img/merge_request.png
index 61b61122b11..c0a62bbaba0 100644
--- a/doc/user/project/merge_requests/img/merge_request.png
+++ b/doc/user/project/merge_requests/img/merge_request.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_request_diff_file_navigation.png b/doc/user/project/merge_requests/img/merge_request_diff_file_navigation.png
index 4eee734ff8d..ac766c99935 100644
--- a/doc/user/project/merge_requests/img/merge_request_diff_file_navigation.png
+++ b/doc/user/project/merge_requests/img/merge_request_diff_file_navigation.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_request_widget.png b/doc/user/project/merge_requests/img/merge_request_widget.png
index 43a945c74d9..6c2317b29b5 100644
--- a/doc/user/project/merge_requests/img/merge_request_widget.png
+++ b/doc/user/project/merge_requests/img/merge_request_widget.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png
index d7f0535d3c5..9487264b41a 100644
--- a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png
+++ b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_msg.png b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_msg.png
index c43f76b058c..761690d1e0c 100644
--- a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_msg.png
+++ b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_msg.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png
index 9629ed99838..2a2101719ba 100644
--- a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png
+++ b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_status.png b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_status.png
index d0691437c65..70fa2efc855 100644
--- a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_status.png
+++ b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_status.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/project_merge_requests_list_view.png b/doc/user/project/merge_requests/img/project_merge_requests_list_view.png
index 702ec1a2949..457716d811c 100644
--- a/doc/user/project/merge_requests/img/project_merge_requests_list_view.png
+++ b/doc/user/project/merge_requests/img/project_merge_requests_list_view.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/remove_source_branch_status.png b/doc/user/project/merge_requests/img/remove_source_branch_status.png
index 1377fab54ec..afd93207e02 100644
--- a/doc/user/project/merge_requests/img/remove_source_branch_status.png
+++ b/doc/user/project/merge_requests/img/remove_source_branch_status.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/revert_changes_commit.png b/doc/user/project/merge_requests/img/revert_changes_commit.png
index a0663e130e9..c9dd0019024 100644
--- a/doc/user/project/merge_requests/img/revert_changes_commit.png
+++ b/doc/user/project/merge_requests/img/revert_changes_commit.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/revert_changes_mr.png b/doc/user/project/merge_requests/img/revert_changes_mr.png
index 8792018ee53..06b841b3002 100644
--- a/doc/user/project/merge_requests/img/revert_changes_mr.png
+++ b/doc/user/project/merge_requests/img/revert_changes_mr.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/squash_edit_form.png b/doc/user/project/merge_requests/img/squash_edit_form.png
index 496c6f44ea7..326d74b68cb 100644
--- a/doc/user/project/merge_requests/img/squash_edit_form.png
+++ b/doc/user/project/merge_requests/img/squash_edit_form.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/squash_mr_commits.png b/doc/user/project/merge_requests/img/squash_mr_commits.png
index 5fc6a8c48bb..dfc1ee38435 100644
--- a/doc/user/project/merge_requests/img/squash_mr_commits.png
+++ b/doc/user/project/merge_requests/img/squash_mr_commits.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/squash_mr_widget.png b/doc/user/project/merge_requests/img/squash_mr_widget.png
index 9cb458b2a35..81334ca9758 100644
--- a/doc/user/project/merge_requests/img/squash_mr_widget.png
+++ b/doc/user/project/merge_requests/img/squash_mr_widget.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/squash_squashed_commit.png b/doc/user/project/merge_requests/img/squash_squashed_commit.png
index 0cf5875f82c..458361c5490 100644
--- a/doc/user/project/merge_requests/img/squash_squashed_commit.png
+++ b/doc/user/project/merge_requests/img/squash_squashed_commit.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/versions.png b/doc/user/project/merge_requests/img/versions.png
index 3883fb4bc1c..8355fd62dcb 100644
--- a/doc/user/project/merge_requests/img/versions.png
+++ b/doc/user/project/merge_requests/img/versions.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/versions_compare.png b/doc/user/project/merge_requests/img/versions_compare.png
index f5bd85dc7c1..0957a0310ac 100644
--- a/doc/user/project/merge_requests/img/versions_compare.png
+++ b/doc/user/project/merge_requests/img/versions_compare.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/versions_dropdown.png b/doc/user/project/merge_requests/img/versions_dropdown.png
index cc70a5bf14b..831c92db2c0 100644
--- a/doc/user/project/merge_requests/img/versions_dropdown.png
+++ b/doc/user/project/merge_requests/img/versions_dropdown.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/versions_system_note.png b/doc/user/project/merge_requests/img/versions_system_note.png
index 90be6298d15..97d552692c9 100644
--- a/doc/user/project/merge_requests/img/versions_system_note.png
+++ b/doc/user/project/merge_requests/img/versions_system_note.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png
index 0c492aca363..31f23be4d3d 100644
--- a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png
+++ b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/wip_mark_as_wip.png b/doc/user/project/merge_requests/img/wip_mark_as_wip.png
index e405879b28a..2c2a263b316 100644
--- a/doc/user/project/merge_requests/img/wip_mark_as_wip.png
+++ b/doc/user/project/merge_requests/img/wip_mark_as_wip.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/wip_unmark_as_wip.png b/doc/user/project/merge_requests/img/wip_unmark_as_wip.png
index d7f8c419945..327ad9a8448 100644
--- a/doc/user/project/merge_requests/img/wip_unmark_as_wip.png
+++ b/doc/user/project/merge_requests/img/wip_unmark_as_wip.png
Binary files differ
diff --git a/doc/user/project/milestones/img/milestones_new_group_milestone.png b/doc/user/project/milestones/img/milestones_new_group_milestone.png
index b6defab101d..a517f0f7537 100644
--- a/doc/user/project/milestones/img/milestones_new_group_milestone.png
+++ b/doc/user/project/milestones/img/milestones_new_group_milestone.png
Binary files differ
diff --git a/doc/user/project/milestones/img/milestones_new_project_milestone.png b/doc/user/project/milestones/img/milestones_new_project_milestone.png
index 9aaff7dfef1..482c73f6568 100644
--- a/doc/user/project/milestones/img/milestones_new_project_milestone.png
+++ b/doc/user/project/milestones/img/milestones_new_project_milestone.png
Binary files differ
diff --git a/doc/user/project/milestones/img/milestones_project_milestone_page.png b/doc/user/project/milestones/img/milestones_project_milestone_page.png
index 9717075b8d0..c17bf350aeb 100644
--- a/doc/user/project/milestones/img/milestones_project_milestone_page.png
+++ b/doc/user/project/milestones/img/milestones_project_milestone_page.png
Binary files differ
diff --git a/doc/user/project/milestones/img/milestones_promote_milestone.png b/doc/user/project/milestones/img/milestones_promote_milestone.png
index 5e7f94c316f..2ef85c5951d 100644
--- a/doc/user/project/milestones/img/milestones_promote_milestone.png
+++ b/doc/user/project/milestones/img/milestones_promote_milestone.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/img/dns_add_new_a_record_example_updated_2018.png
index fa72df66587..0150329d4b2 100644
--- a/doc/user/project/pages/img/dns_add_new_a_record_example_updated_2018.png
+++ b/doc/user/project/pages/img/dns_add_new_a_record_example_updated_2018.png
Binary files differ
diff --git a/doc/user/project/pages/img/pages_create_project.png b/doc/user/project/pages/img/pages_create_project.png
index be47f9d2a44..69e84b84984 100644
--- a/doc/user/project/pages/img/pages_create_project.png
+++ b/doc/user/project/pages/img/pages_create_project.png
Binary files differ
diff --git a/doc/user/project/pages/img/pages_dns_details.png b/doc/user/project/pages/img/pages_dns_details.png
index 274e98fde4d..3e57f43f7ba 100644
--- a/doc/user/project/pages/img/pages_dns_details.png
+++ b/doc/user/project/pages/img/pages_dns_details.png
Binary files differ
diff --git a/doc/user/project/pages/img/pages_multiple_domains.png b/doc/user/project/pages/img/pages_multiple_domains.png
index 6bc92db6b41..76c39101439 100644
--- a/doc/user/project/pages/img/pages_multiple_domains.png
+++ b/doc/user/project/pages/img/pages_multiple_domains.png
Binary files differ
diff --git a/doc/user/project/pages/img/pages_remove.png b/doc/user/project/pages/img/pages_remove.png
index b064310380e..10299880247 100644
--- a/doc/user/project/pages/img/pages_remove.png
+++ b/doc/user/project/pages/img/pages_remove.png
Binary files differ
diff --git a/doc/user/project/pages/img/pages_upload_cert.png b/doc/user/project/pages/img/pages_upload_cert.png
index dc431ea3fef..64e5f8eced1 100644
--- a/doc/user/project/pages/img/pages_upload_cert.png
+++ b/doc/user/project/pages/img/pages_upload_cert.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
index 89c69cac9a5..d870f9e6505 100644
--- a/doc/user/project/pages/img/verify_your_domain.png
+++ b/doc/user/project/pages/img/verify_your_domain.png
Binary files differ
diff --git a/doc/user/project/pipelines/img/job_artifacts_pipelines_page.png b/doc/user/project/pipelines/img/job_artifacts_pipelines_page.png
index 3ccce4f9bb4..983f903ca72 100644
--- a/doc/user/project/pipelines/img/job_artifacts_pipelines_page.png
+++ b/doc/user/project/pipelines/img/job_artifacts_pipelines_page.png
Binary files differ
diff --git a/doc/user/project/pipelines/img/pipeline_schedule_play.png b/doc/user/project/pipelines/img/pipeline_schedule_play.png
index f594ceee19d..ec6eb0d156b 100644
--- a/doc/user/project/pipelines/img/pipeline_schedule_play.png
+++ b/doc/user/project/pipelines/img/pipeline_schedule_play.png
Binary files differ
diff --git a/doc/user/project/pipelines/img/pipeline_schedule_variables.png b/doc/user/project/pipelines/img/pipeline_schedule_variables.png
index 47a0c6f3697..74692add93a 100644
--- a/doc/user/project/pipelines/img/pipeline_schedule_variables.png
+++ b/doc/user/project/pipelines/img/pipeline_schedule_variables.png
Binary files differ
diff --git a/doc/user/project/pipelines/img/pipeline_schedules_list.png b/doc/user/project/pipelines/img/pipeline_schedules_list.png
index 2ab2061db94..541fe4f9b1d 100644
--- a/doc/user/project/pipelines/img/pipeline_schedules_list.png
+++ b/doc/user/project/pipelines/img/pipeline_schedules_list.png
Binary files differ
diff --git a/doc/user/project/pipelines/img/pipeline_schedules_new_form.png b/doc/user/project/pipelines/img/pipeline_schedules_new_form.png
index 5a0e5965992..95203ec861b 100644
--- a/doc/user/project/pipelines/img/pipeline_schedules_new_form.png
+++ b/doc/user/project/pipelines/img/pipeline_schedules_new_form.png
Binary files differ
diff --git a/doc/user/project/pipelines/img/pipeline_schedules_ownership.png b/doc/user/project/pipelines/img/pipeline_schedules_ownership.png
index 31ed83abb4d..8fc5c5fbc82 100644
--- a/doc/user/project/pipelines/img/pipeline_schedules_ownership.png
+++ b/doc/user/project/pipelines/img/pipeline_schedules_ownership.png
Binary files differ
diff --git a/doc/user/project/repository/branches/img/delete_merged_branches.png b/doc/user/project/repository/branches/img/delete_merged_branches.png
index 1856a624f74..649a758b95f 100644
--- a/doc/user/project/repository/branches/img/delete_merged_branches.png
+++ b/doc/user/project/repository/branches/img/delete_merged_branches.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png b/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png
index 8e26d98f1b0..6e2ff33eebb 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png
+++ b/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png b/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png
index 5c14df36d73..ae0a8696c6c 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png
+++ b/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.png b/doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.png
index 088ecfa6d89..e1d44f15f3f 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.png
+++ b/doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.png b/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.png
index 4e3392406b1..763a677f94a 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.png
+++ b/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.png b/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.png
index 766970dee81..1b6fa3fc2e2 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.png
+++ b/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.png
Binary files differ
diff --git a/doc/user/project/repository/img/compare_branches.png b/doc/user/project/repository/img/compare_branches.png
index d7ab587f030..52d5c518c45 100644
--- a/doc/user/project/repository/img/compare_branches.png
+++ b/doc/user/project/repository/img/compare_branches.png
Binary files differ
diff --git a/doc/user/project/repository/img/repository_languages.png b/doc/user/project/repository/img/repository_languages.png
index d9fb1278e06..5977ad7faae 100644
--- a/doc/user/project/repository/img/repository_languages.png
+++ b/doc/user/project/repository/img/repository_languages.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_branch_dropdown.png b/doc/user/project/repository/img/web_editor_new_branch_dropdown.png
index 31edb6bde3a..a6edea1fcce 100644
--- a/doc/user/project/repository/img/web_editor_new_branch_dropdown.png
+++ b/doc/user/project/repository/img/web_editor_new_branch_dropdown.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_branch_from_issue.png b/doc/user/project/repository/img/web_editor_new_branch_from_issue.png
index 4729f5383c0..4e156b8adc8 100644
--- a/doc/user/project/repository/img/web_editor_new_branch_from_issue.png
+++ b/doc/user/project/repository/img/web_editor_new_branch_from_issue.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_branch_page.png b/doc/user/project/repository/img/web_editor_new_branch_page.png
index 8d82f981527..7bb8b9e29e3 100644
--- a/doc/user/project/repository/img/web_editor_new_branch_page.png
+++ b/doc/user/project/repository/img/web_editor_new_branch_page.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_directory_dialog.png b/doc/user/project/repository/img/web_editor_new_directory_dialog.png
index 1c9beff8849..590989c360e 100644
--- a/doc/user/project/repository/img/web_editor_new_directory_dialog.png
+++ b/doc/user/project/repository/img/web_editor_new_directory_dialog.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_directory_dropdown.png b/doc/user/project/repository/img/web_editor_new_directory_dropdown.png
index ede691f6f74..efa3087fc0c 100644
--- a/doc/user/project/repository/img/web_editor_new_directory_dropdown.png
+++ b/doc/user/project/repository/img/web_editor_new_directory_dropdown.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_file_dropdown.png b/doc/user/project/repository/img/web_editor_new_file_dropdown.png
index 13a4d721039..b40fb1ce58d 100644
--- a/doc/user/project/repository/img/web_editor_new_file_dropdown.png
+++ b/doc/user/project/repository/img/web_editor_new_file_dropdown.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_push_widget.png b/doc/user/project/repository/img/web_editor_new_push_widget.png
index 77756876d4f..8957b5d6a6b 100644
--- a/doc/user/project/repository/img/web_editor_new_push_widget.png
+++ b/doc/user/project/repository/img/web_editor_new_push_widget.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_new_tag_dropdown.png b/doc/user/project/repository/img/web_editor_new_tag_dropdown.png
index b52d5cabdf2..33e8ed891b5 100644
--- a/doc/user/project/repository/img/web_editor_new_tag_dropdown.png
+++ b/doc/user/project/repository/img/web_editor_new_tag_dropdown.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_start_new_merge_request.png b/doc/user/project/repository/img/web_editor_start_new_merge_request.png
index 384e8320f15..85f4769661a 100644
--- a/doc/user/project/repository/img/web_editor_start_new_merge_request.png
+++ b/doc/user/project/repository/img/web_editor_start_new_merge_request.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_template_dropdown_buttons.png b/doc/user/project/repository/img/web_editor_template_dropdown_buttons.png
index f21183125f6..4608843b1f4 100644
--- a/doc/user/project/repository/img/web_editor_template_dropdown_buttons.png
+++ b/doc/user/project/repository/img/web_editor_template_dropdown_buttons.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_template_dropdown_first_file.png b/doc/user/project/repository/img/web_editor_template_dropdown_first_file.png
index 7f31c2a8887..a4440ec3cc9 100644
--- a/doc/user/project/repository/img/web_editor_template_dropdown_first_file.png
+++ b/doc/user/project/repository/img/web_editor_template_dropdown_first_file.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_upload_file_dialog.png b/doc/user/project/repository/img/web_editor_upload_file_dialog.png
index 04e951406ad..c0e9a99aa61 100644
--- a/doc/user/project/repository/img/web_editor_upload_file_dialog.png
+++ b/doc/user/project/repository/img/web_editor_upload_file_dialog.png
Binary files differ
diff --git a/doc/user/project/repository/img/web_editor_upload_file_dropdown.png b/doc/user/project/repository/img/web_editor_upload_file_dropdown.png
index b8c766d4b99..c80a9ae4b3d 100644
--- a/doc/user/project/repository/img/web_editor_upload_file_dropdown.png
+++ b/doc/user/project/repository/img/web_editor_upload_file_dropdown.png
Binary files differ
diff --git a/doc/user/project/settings/img/import_export_download_export.png b/doc/user/project/settings/img/import_export_download_export.png
index 4945590e3e8..668254073e8 100644
--- a/doc/user/project/settings/img/import_export_download_export.png
+++ b/doc/user/project/settings/img/import_export_download_export.png
Binary files differ
diff --git a/doc/user/project/settings/img/import_export_export_button.png b/doc/user/project/settings/img/import_export_export_button.png
index eef79821f8b..7f21bb2335b 100644
--- a/doc/user/project/settings/img/import_export_export_button.png
+++ b/doc/user/project/settings/img/import_export_export_button.png
Binary files differ
diff --git a/doc/user/project/settings/img/import_export_new_project.png b/doc/user/project/settings/img/import_export_new_project.png
index 9dd509dc4a0..b335700c5be 100644
--- a/doc/user/project/settings/img/import_export_new_project.png
+++ b/doc/user/project/settings/img/import_export_new_project.png
Binary files differ
diff --git a/doc/user/project/settings/img/import_export_select_file.png b/doc/user/project/settings/img/import_export_select_file.png
index fb831dca32b..e1e5e031d81 100644
--- a/doc/user/project/settings/img/import_export_select_file.png
+++ b/doc/user/project/settings/img/import_export_select_file.png
Binary files differ
diff --git a/doc/user/project/settings/img/settings_edit_button.png b/doc/user/project/settings/img/settings_edit_button.png
index 9f3a8330e3a..32bcda03c7e 100644
--- a/doc/user/project/settings/img/settings_edit_button.png
+++ b/doc/user/project/settings/img/settings_edit_button.png
Binary files differ
diff --git a/doc/user/project/settings/img/sharing_and_permissions_settings.png b/doc/user/project/settings/img/sharing_and_permissions_settings.png
index 0f9cf9512af..f5e3e32f95c 100644
--- a/doc/user/project/settings/img/sharing_and_permissions_settings.png
+++ b/doc/user/project/settings/img/sharing_and_permissions_settings.png
Binary files differ
diff --git a/doc/user/project/web_ide/img/open_web_ide.png b/doc/user/project/web_ide/img/open_web_ide.png
index d1192daf506..02a5a564472 100644
--- a/doc/user/project/web_ide/img/open_web_ide.png
+++ b/doc/user/project/web_ide/img/open_web_ide.png
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_create_home_page.png b/doc/user/project/wiki/img/wiki_create_home_page.png
index f50f564034c..658af33d76e 100644
--- a/doc/user/project/wiki/img/wiki_create_home_page.png
+++ b/doc/user/project/wiki/img/wiki_create_home_page.png
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_create_new_page.png b/doc/user/project/wiki/img/wiki_create_new_page.png
index c19124a8923..8954ec0d3a8 100644
--- a/doc/user/project/wiki/img/wiki_create_new_page.png
+++ b/doc/user/project/wiki/img/wiki_create_new_page.png
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_create_new_page_modal.png b/doc/user/project/wiki/img/wiki_create_new_page_modal.png
index ece437967dc..b800508901b 100644
--- a/doc/user/project/wiki/img/wiki_create_new_page_modal.png
+++ b/doc/user/project/wiki/img/wiki_create_new_page_modal.png
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_move_page_1.png b/doc/user/project/wiki/img/wiki_move_page_1.png
index 0331c9d3a5c..189fcc9a845 100644
--- a/doc/user/project/wiki/img/wiki_move_page_1.png
+++ b/doc/user/project/wiki/img/wiki_move_page_1.png
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_move_page_2.png b/doc/user/project/wiki/img/wiki_move_page_2.png
index a8e0c055051..63e6ddb29c1 100644
--- a/doc/user/project/wiki/img/wiki_move_page_2.png
+++ b/doc/user/project/wiki/img/wiki_move_page_2.png
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_page_history.png b/doc/user/project/wiki/img/wiki_page_history.png
index 0e6af1b468d..5a1ae295ed2 100644
--- a/doc/user/project/wiki/img/wiki_page_history.png
+++ b/doc/user/project/wiki/img/wiki_page_history.png
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_sidebar.png b/doc/user/project/wiki/img/wiki_sidebar.png
index 59814e2a06e..ff39c861a73 100644
--- a/doc/user/project/wiki/img/wiki_sidebar.png
+++ b/doc/user/project/wiki/img/wiki_sidebar.png
Binary files differ
diff --git a/doc/user/search/img/issue_search_by_term.png b/doc/user/search/img/issue_search_by_term.png
index 3cefa3adb8b..64450c6a891 100644
--- a/doc/user/search/img/issue_search_by_term.png
+++ b/doc/user/search/img/issue_search_by_term.png
Binary files differ
diff --git a/doc/user/search/img/issue_search_filter.png b/doc/user/search/img/issue_search_filter.png
index f357abd6bac..d4de3ff7656 100644
--- a/doc/user/search/img/issue_search_filter.png
+++ b/doc/user/search/img/issue_search_filter.png
Binary files differ
diff --git a/doc/user/search/img/issues_mrs_shortcut.png b/doc/user/search/img/issues_mrs_shortcut.png
index cf43df98aa0..2fe1350c806 100644
--- a/doc/user/search/img/issues_mrs_shortcut.png
+++ b/doc/user/search/img/issues_mrs_shortcut.png
Binary files differ
diff --git a/doc/user/search/img/project_search.png b/doc/user/search/img/project_search.png
index 0b76d7d6038..b2525b2c771 100644
--- a/doc/user/search/img/project_search.png
+++ b/doc/user/search/img/project_search.png
Binary files differ
diff --git a/doc/workflow/ci_mr.png b/doc/workflow/ci_mr.png
index 77423c68190..85a609cb814 100644
--- a/doc/workflow/ci_mr.png
+++ b/doc/workflow/ci_mr.png
Binary files differ
diff --git a/doc/workflow/environment_branches.png b/doc/workflow/environment_branches.png
index 0941a4cad9c..0aff33c6bb8 100644
--- a/doc/workflow/environment_branches.png
+++ b/doc/workflow/environment_branches.png
Binary files differ
diff --git a/doc/workflow/forking/branch_select.png b/doc/workflow/forking/branch_select.png
index 3e82afca75b..77236137190 100644
--- a/doc/workflow/forking/branch_select.png
+++ b/doc/workflow/forking/branch_select.png
Binary files differ
diff --git a/doc/workflow/forking/merge_request.png b/doc/workflow/forking/merge_request.png
index 294775e1fdd..407ddfb4799 100644
--- a/doc/workflow/forking/merge_request.png
+++ b/doc/workflow/forking/merge_request.png
Binary files differ
diff --git a/doc/workflow/git_pull.png b/doc/workflow/git_pull.png
index 2dd06b56c56..0e56e59471c 100644
--- a/doc/workflow/git_pull.png
+++ b/doc/workflow/git_pull.png
Binary files differ
diff --git a/doc/workflow/gitlab_flow.png b/doc/workflow/gitlab_flow.png
index c3562cc69a8..a6f3c947843 100644
--- a/doc/workflow/gitlab_flow.png
+++ b/doc/workflow/gitlab_flow.png
Binary files differ
diff --git a/doc/workflow/good_commit.png b/doc/workflow/good_commit.png
index c3664aa97f2..ceb0d4b1691 100644
--- a/doc/workflow/good_commit.png
+++ b/doc/workflow/good_commit.png
Binary files differ
diff --git a/doc/workflow/img/file_finder_find_button.png b/doc/workflow/img/file_finder_find_button.png
index 23139cc00c5..0c2d7d7bc73 100644
--- a/doc/workflow/img/file_finder_find_button.png
+++ b/doc/workflow/img/file_finder_find_button.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_fork_button.png b/doc/workflow/img/forking_workflow_fork_button.png
index 29854e6c516..941d5363c35 100644
--- a/doc/workflow/img/forking_workflow_fork_button.png
+++ b/doc/workflow/img/forking_workflow_fork_button.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_path_taken_error.png b/doc/workflow/img/forking_workflow_path_taken_error.png
index 9365fd13200..df938da5677 100644
--- a/doc/workflow/img/forking_workflow_path_taken_error.png
+++ b/doc/workflow/img/forking_workflow_path_taken_error.png
Binary files differ
diff --git a/doc/workflow/img/notification_group_settings.png b/doc/workflow/img/notification_group_settings.png
index fc096f46901..ed5e9459216 100644
--- a/doc/workflow/img/notification_group_settings.png
+++ b/doc/workflow/img/notification_group_settings.png
Binary files differ
diff --git a/doc/workflow/img/notification_project_settings.png b/doc/workflow/img/notification_project_settings.png
index 006432f65c9..e2db2037d94 100644
--- a/doc/workflow/img/notification_project_settings.png
+++ b/doc/workflow/img/notification_project_settings.png
Binary files differ
diff --git a/doc/workflow/img/todo_list_item.png b/doc/workflow/img/todo_list_item.png
index 076069b651e..91bbf9e5373 100644
--- a/doc/workflow/img/todo_list_item.png
+++ b/doc/workflow/img/todo_list_item.png
Binary files differ
diff --git a/doc/workflow/img/todos_add_todo_sidebar.png b/doc/workflow/img/todos_add_todo_sidebar.png
index 3fa37067d1e..aefec7a2d9c 100644
--- a/doc/workflow/img/todos_add_todo_sidebar.png
+++ b/doc/workflow/img/todos_add_todo_sidebar.png
Binary files differ
diff --git a/doc/workflow/img/todos_mark_done_sidebar.png b/doc/workflow/img/todos_mark_done_sidebar.png
index a8e756a71db..2badd880b40 100644
--- a/doc/workflow/img/todos_mark_done_sidebar.png
+++ b/doc/workflow/img/todos_mark_done_sidebar.png
Binary files differ
diff --git a/doc/workflow/merge_request.png b/doc/workflow/merge_request.png
index 08dfc7f2468..010e95983fc 100644
--- a/doc/workflow/merge_request.png
+++ b/doc/workflow/merge_request.png
Binary files differ
diff --git a/doc/workflow/messy_flow.png b/doc/workflow/messy_flow.png
index 7e72e2a3be6..4fa22d2bb5d 100644
--- a/doc/workflow/messy_flow.png
+++ b/doc/workflow/messy_flow.png
Binary files differ
diff --git a/doc/workflow/mr_inline_comments.png b/doc/workflow/mr_inline_comments.png
index 6a2e66a01ba..a18801f56e4 100644
--- a/doc/workflow/mr_inline_comments.png
+++ b/doc/workflow/mr_inline_comments.png
Binary files differ
diff --git a/doc/workflow/production_branch.png b/doc/workflow/production_branch.png
index 648d5d5c92e..c132d51bfb6 100644
--- a/doc/workflow/production_branch.png
+++ b/doc/workflow/production_branch.png
Binary files differ
diff --git a/doc/workflow/rebase.png b/doc/workflow/rebase.png
index 8b9bb61a5cc..fe865177ba8 100644
--- a/doc/workflow/rebase.png
+++ b/doc/workflow/rebase.png
Binary files differ
diff --git a/doc/workflow/release_branches.png b/doc/workflow/release_branches.png
index 5194d75a667..0a7f61d0248 100644
--- a/doc/workflow/release_branches.png
+++ b/doc/workflow/release_branches.png
Binary files differ
diff --git a/doc/workflow/releases/new_tag.png b/doc/workflow/releases/new_tag.png
index 97519e5808f..6137ad2ee56 100644
--- a/doc/workflow/releases/new_tag.png
+++ b/doc/workflow/releases/new_tag.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_detect_host_keys.png b/doc/workflow/repository_mirroring/repository_mirroring_detect_host_keys.png
index 333648942f8..2377a4a6516 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_detect_host_keys.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_detect_host_keys.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_diverged_branch_push.png b/doc/workflow/repository_mirroring/repository_mirroring_diverged_branch_push.png
index 038b05cb31d..786bd23eee6 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_diverged_branch_push.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_diverged_branch_push.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_main.png b/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_main.png
index 99d429a1802..d8af5ce129e 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_main.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_main.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_settings.png b/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_settings.png
index 0ab07afa3cc..a10102e97ac 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_settings.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_hard_failed_settings.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_pull_advanced_host_keys.png b/doc/workflow/repository_mirroring/repository_mirroring_pull_advanced_host_keys.png
index 5da5a7436bb..1f1b3e1d5fb 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_pull_advanced_host_keys.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_pull_advanced_host_keys.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_pull_settings.png b/doc/workflow/repository_mirroring/repository_mirroring_pull_settings.png
index 4b9085302a1..b8dfddb3d02 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_pull_settings.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_pull_settings.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_pull_settings_for_ssh.png b/doc/workflow/repository_mirroring/repository_mirroring_pull_settings_for_ssh.png
index 8c2efdafa43..8f1de1d3003 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_pull_settings_for_ssh.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_pull_settings_for_ssh.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_ssh_host_keys_verified.png b/doc/workflow/repository_mirroring/repository_mirroring_ssh_host_keys_verified.png
index 93f3a532a0e..930d10a0822 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_ssh_host_keys_verified.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_ssh_host_keys_verified.png
Binary files differ
diff --git a/doc/workflow/repository_mirroring/repository_mirroring_ssh_public_key_authentication.png b/doc/workflow/repository_mirroring/repository_mirroring_ssh_public_key_authentication.png
index 6997ad511d9..adc1eedac44 100644
--- a/doc/workflow/repository_mirroring/repository_mirroring_ssh_public_key_authentication.png
+++ b/doc/workflow/repository_mirroring/repository_mirroring_ssh_public_key_authentication.png
Binary files differ
diff --git a/doc/workflow/time-tracking/time-tracking-example.png b/doc/workflow/time-tracking/time-tracking-example.png
index bbcabb602d6..a96e4da7f74 100644
--- a/doc/workflow/time-tracking/time-tracking-example.png
+++ b/doc/workflow/time-tracking/time-tracking-example.png
Binary files differ
diff --git a/doc/workflow/time-tracking/time-tracking-sidebar.png b/doc/workflow/time-tracking/time-tracking-sidebar.png
index d1ff5571f95..22124afed6f 100644
--- a/doc/workflow/time-tracking/time-tracking-sidebar.png
+++ b/doc/workflow/time-tracking/time-tracking-sidebar.png
Binary files differ
diff --git a/lib/api/api.rb b/lib/api/api.rb
index e2ad3c5f4e3..c000666d992 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -99,12 +99,13 @@ module API
mount ::API::Features
mount ::API::Files
mount ::API::GroupBoards
- mount ::API::Groups
mount ::API::GroupMilestones
+ mount ::API::Groups
+ mount ::API::GroupVariables
mount ::API::Internal
mount ::API::Issues
- mount ::API::Jobs
mount ::API::JobArtifacts
+ mount ::API::Jobs
mount ::API::Keys
mount ::API::Labels
mount ::API::Lint
@@ -122,11 +123,12 @@ module API
mount ::API::ProjectExport
mount ::API::ProjectImport
mount ::API::ProjectHooks
- mount ::API::Projects
mount ::API::ProjectMilestones
+ mount ::API::Projects
mount ::API::ProjectSnapshots
mount ::API::ProjectSnippets
mount ::API::ProtectedBranches
+ mount ::API::ProtectedTags
mount ::API::Repositories
mount ::API::Runner
mount ::API::Runners
@@ -143,7 +145,6 @@ module API
mount ::API::Triggers
mount ::API::Users
mount ::API::Variables
- mount ::API::GroupVariables
mount ::API::Version
mount ::API::Wikis
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index c3d93996816..bde4b3ff4f6 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -100,7 +100,7 @@ module API
end
def can_award_awardable?
- awardable.user_can_award?(current_user, params[:name])
+ awardable.user_can_award?(current_user)
end
def awardable
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 06262f0f991..95b25d7351a 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -429,6 +429,11 @@ module API
expose :merge_access_levels, using: Entities::ProtectedRefAccess
end
+ class ProtectedTag < Grape::Entity
+ expose :name
+ expose :create_access_levels, using: Entities::ProtectedRefAccess
+ end
+
class Milestone < Grape::Entity
expose :id, :iid
expose :project_id, if: -> (entity, options) { entity&.project_id }
diff --git a/lib/api/group_milestones.rb b/lib/api/group_milestones.rb
index 93fa0b95857..4b4352c2b27 100644
--- a/lib/api/group_milestones.rb
+++ b/lib/api/group_milestones.rb
@@ -41,7 +41,7 @@ module API
use :optional_params
end
post ":id/milestones" do
- authorize! :admin_milestones, user_group
+ authorize! :admin_milestone, user_group
create_milestone_for(user_group)
end
@@ -53,11 +53,21 @@ module API
use :update_params
end
put ":id/milestones/:milestone_id" do
- authorize! :admin_milestones, user_group
+ authorize! :admin_milestone, user_group
update_milestone_for(user_group)
end
+ desc 'Remove a project milestone'
+ delete ":id/milestones/:milestone_id" do
+ authorize! :admin_milestone, user_group
+
+ milestone = user_group.milestones.find(params[:milestone_id])
+ Milestones::DestroyService.new(user_group, current_user).execute(milestone)
+
+ status(204)
+ end
+
desc 'Get all issues for a single group milestone' do
success Entities::IssueBasic
end
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
index e2984b08eca..7b1f5c2584b 100644
--- a/lib/api/helpers/notes_helpers.rb
+++ b/lib/api/helpers/notes_helpers.rb
@@ -92,10 +92,7 @@ module API
parent = noteable_parent(noteable)
- if opts[:created_at]
- opts.delete(:created_at) unless
- current_user.admin? || parent.owned_by?(current_user)
- end
+ opts.delete(:created_at) unless current_user.can?(:set_note_created_at, policy_object)
opts[:updated_at] = opts[:created_at] if opts[:created_at]
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index bda05d1795b..cedfd2fbaa0 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -172,11 +172,8 @@ module API
authorize! :create_issue, user_project
- # Setting created_at time or iid only allowed for admins and project owners
- unless current_user.admin? || user_project.owner == current_user
- params.delete(:created_at)
- params.delete(:iid)
- end
+ params.delete(:created_at) unless current_user.can?(:set_issue_created_at, user_project)
+ params.delete(:iid) unless current_user.can?(:set_issue_iid, user_project)
issue_params = declared_params(include_missing: false)
@@ -216,8 +213,8 @@ module API
issue = user_project.issues.find_by!(iid: params.delete(:issue_iid))
authorize! :update_issue, issue
- # Setting created_at time only allowed for admins and project owners
- unless current_user.admin? || user_project.owner == current_user
+ # Setting created_at time only allowed for admins and project/group owners
+ unless current_user.admin? || user_project.owner == current_user || current_user.owned_groups.include?(user_project.owner)
params.delete(:updated_at)
end
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 306dc0e63d7..72cf32d7717 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -64,7 +64,8 @@ module API
delete ":id/milestones/:milestone_id" do
authorize! :admin_milestone, user_project
- user_project.milestones.find(params[:milestone_id]).destroy
+ milestone = user_project.milestones.find(params[:milestone_id])
+ Milestones::DestroyService.new(user_project, current_user).execute(milestone)
status(204)
end
diff --git a/lib/api/protected_tags.rb b/lib/api/protected_tags.rb
new file mode 100644
index 00000000000..bf0a7184e1c
--- /dev/null
+++ b/lib/api/protected_tags.rb
@@ -0,0 +1,79 @@
+module API
+ class ProtectedTags < Grape::API
+ include PaginationParams
+
+ TAG_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(name: API::NO_SLASH_URL_PART_REGEX)
+
+ before { authorize_admin_project }
+
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
+ desc "Get a project's protected tags" do
+ detail 'This feature was introduced in GitLab 11.3.'
+ success Entities::ProtectedTag
+ end
+ params do
+ use :pagination
+ end
+ get ':id/protected_tags' do
+ protected_tags = user_project.protected_tags.preload(:create_access_levels)
+
+ present paginate(protected_tags), with: Entities::ProtectedTag, project: user_project
+ end
+
+ desc 'Get a single protected tag' do
+ detail 'This feature was introduced in GitLab 11.3.'
+ success Entities::ProtectedTag
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the tag or wildcard'
+ end
+ get ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
+ protected_tag = user_project.protected_tags.find_by!(name: params[:name])
+
+ present protected_tag, with: Entities::ProtectedTag, project: user_project
+ end
+
+ desc 'Protect a single tag or wildcard' do
+ detail 'This feature was introduced in GitLab 11.3.'
+ success Entities::ProtectedTag
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the protected tag'
+ optional :create_access_level, type: Integer, default: Gitlab::Access::MAINTAINER,
+ values: ProtectedRefAccess::ALLOWED_ACCESS_LEVELS,
+ desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)'
+ end
+ post ':id/protected_tags' do
+ protected_tags_params = {
+ name: params[:name],
+ create_access_levels_attributes: [{ access_level: params[:create_access_level] }]
+ }
+
+ protected_tag = ::ProtectedTags::CreateService.new(user_project,
+ current_user,
+ protected_tags_params).execute
+
+ if protected_tag.persisted?
+ present protected_tag, with: Entities::ProtectedTag, project: user_project
+ else
+ render_api_error!(protected_tag.errors.full_messages, 422)
+ end
+ end
+
+ desc 'Unprotect a single tag' do
+ detail 'This feature was introduced in GitLab 11.3.'
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the protected tag'
+ end
+ delete ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
+ protected_tag = user_project.protected_tags.find_by!(name: params[:name])
+
+ destroy_conditionally!(protected_tag)
+ end
+ end
+ end
+end
diff --git a/lib/banzai/reference_parser/merge_request_parser.rb b/lib/banzai/reference_parser/merge_request_parser.rb
index a370ff5b5b3..9e5d55f72bc 100644
--- a/lib/banzai/reference_parser/merge_request_parser.rb
+++ b/lib/banzai/reference_parser/merge_request_parser.rb
@@ -14,11 +14,12 @@ module Banzai
# Eager loading these ensures we don't end up running dozens of
# queries in this process.
target_project: [
- { namespace: :owner },
+ { namespace: [:owner, :route] },
{ group: [:owners, :group_members] },
:invited_groups,
:project_members,
- :project_feature
+ :project_feature,
+ :route
]
}),
self.class.data_attribute
diff --git a/lib/feature.rb b/lib/feature.rb
index 09c5ef3ad94..24dbcb32fc0 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -47,7 +47,8 @@ class Feature
end
def disabled?(key, thing = nil)
- !enabled?(key, thing)
+ # we need to make different method calls to make it easy to mock / define expectations in test mode
+ thing.nil? ? !enabled?(key) : !enabled?(key, thing)
end
def enable(key, thing = true)
diff --git a/lib/gitlab/auth/ldap/access.rb b/lib/gitlab/auth/ldap/access.rb
index 865185eb5db..eeab7791643 100644
--- a/lib/gitlab/auth/ldap/access.rb
+++ b/lib/gitlab/auth/ldap/access.rb
@@ -19,8 +19,10 @@ module Gitlab
# Whether user is allowed, or not, we should update
# permissions to keep things clean
if access.allowed?
- access.update_user
- Users::UpdateService.new(user, user: user, last_credential_check_at: Time.now).execute
+ unless Gitlab::Database.read_only?
+ access.update_user
+ Users::UpdateService.new(user, user: user, last_credential_check_at: Time.now).execute
+ end
true
else
@@ -60,6 +62,12 @@ module Gitlab
false
end
+ def update_user
+ # no-op in CE
+ end
+
+ private
+
def adapter
@adapter ||= Gitlab::Auth::LDAP::Adapter.new(provider)
end
@@ -68,16 +76,16 @@ module Gitlab
Gitlab::Auth::LDAP::Config.new(provider)
end
- def find_ldap_user
- Gitlab::Auth::LDAP::Person.find_by_dn(ldap_identity.extern_uid, adapter)
- end
-
def ldap_user
return unless provider
@ldap_user ||= find_ldap_user
end
+ def find_ldap_user
+ Gitlab::Auth::LDAP::Person.find_by_dn(ldap_identity.extern_uid, adapter)
+ end
+
def block_user(user, reason)
user.ldap_block
@@ -102,10 +110,6 @@ module Gitlab
"unblocking Gitlab user \"#{user.name}\" (#{user.email})"
)
end
-
- def update_user
- # no-op in CE
- end
end
end
end
diff --git a/lib/gitlab/auth/o_auth/provider.rb b/lib/gitlab/auth/o_auth/provider.rb
index e73743944a9..26da9d09ccc 100644
--- a/lib/gitlab/auth/o_auth/provider.rb
+++ b/lib/gitlab/auth/o_auth/provider.rb
@@ -29,6 +29,7 @@ module Gitlab
def self.enabled?(name)
return true if name == 'database'
+ return true if self.ldap_provider?(name) && providers.include?(name.to_sym)
Gitlab::Auth.omniauth_enabled? && providers.include?(name.to_sym)
end
diff --git a/lib/gitlab/bitbucket_server_import/importer.rb b/lib/gitlab/bitbucket_server_import/importer.rb
index 268d21a77d1..b591d94668f 100644
--- a/lib/gitlab/bitbucket_server_import/importer.rb
+++ b/lib/gitlab/bitbucket_server_import/importer.rb
@@ -1,7 +1,10 @@
+# frozen_string_literal: true
+
module Gitlab
module BitbucketServerImport
class Importer
include Gitlab::ShellAdapter
+
attr_reader :recover_missing_commits
attr_reader :project, :project_key, :repository_slug, :client, :errors, :users
@@ -175,21 +178,18 @@ module Gitlab
description = ''
description += @formatter.author_line(pull_request.author) unless find_user_id(pull_request.author_email)
description += pull_request.description if pull_request.description
-
- source_branch_sha = pull_request.source_branch_sha
- target_branch_sha = pull_request.target_branch_sha
author_id = gitlab_user_id(pull_request.author_email)
attributes = {
iid: pull_request.iid,
title: pull_request.title,
description: description,
- source_project: project,
+ source_project_id: project.id,
source_branch: Gitlab::Git.ref_name(pull_request.source_branch_name),
- source_branch_sha: source_branch_sha,
- target_project: project,
+ source_branch_sha: pull_request.source_branch_sha,
+ target_project_id: project.id,
target_branch: Gitlab::Git.ref_name(pull_request.target_branch_name),
- target_branch_sha: target_branch_sha,
+ target_branch_sha: pull_request.target_branch_sha,
state: pull_request.state,
author_id: author_id,
assignee_id: nil,
@@ -197,7 +197,9 @@ module Gitlab
updated_at: pull_request.updated_at
}
- merge_request = project.merge_requests.create!(attributes)
+ creator = Gitlab::Import::MergeRequestCreator.new(project)
+ merge_request = creator.execute(attributes)
+
import_pull_request_comments(pull_request, merge_request) if merge_request.persisted?
end
diff --git a/lib/gitlab/ci/status/build/failed.rb b/lib/gitlab/ci/status/build/failed.rb
index 703f0b9217b..508b4814631 100644
--- a/lib/gitlab/ci/status/build/failed.rb
+++ b/lib/gitlab/ci/status/build/failed.rb
@@ -32,7 +32,7 @@ module Gitlab
end
def description
- "<br> (#{failure_reason_message})"
+ "- (#{failure_reason_message})"
end
def failure_reason_message
diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb
index 5c1baa19b66..1f012043e56 100644
--- a/lib/gitlab/diff/highlight.rb
+++ b/lib/gitlab/diff/highlight.rb
@@ -37,7 +37,7 @@ module Gitlab
end
end
- diff_line.text = rich_line
+ diff_line.rich_text = rich_line
diff_line
end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
index 1faf7770634..1ab6df0b6ae 100644
--- a/lib/gitlab/diff/line.rb
+++ b/lib/gitlab/diff/line.rb
@@ -1,16 +1,17 @@
module Gitlab
module Diff
class Line
- SERIALIZE_KEYS = %i(line_code text type index old_pos new_pos).freeze
+ SERIALIZE_KEYS = %i(line_code rich_text text type index old_pos new_pos).freeze
attr_reader :line_code, :type, :index, :old_pos, :new_pos
attr_writer :rich_text
attr_accessor :text
- def initialize(text, type, index, old_pos, new_pos, parent_file: nil, line_code: nil)
+ def initialize(text, type, index, old_pos, new_pos, parent_file: nil, line_code: nil, rich_text: nil)
@text, @type, @index = text, type, index
@old_pos, @new_pos = old_pos, new_pos
@parent_file = parent_file
+ @rich_text = rich_text
# When line code is not provided from cache store we build it
# using the parent_file(Diff::File or Conflict::File).
@@ -18,7 +19,7 @@ module Gitlab
end
def self.init_from_hash(hash)
- new(hash[:text], hash[:type], hash[:index], hash[:old_pos], hash[:new_pos], line_code: hash[:line_code])
+ new(hash[:text], hash[:type], hash[:index], hash[:old_pos], hash[:new_pos], line_code: hash[:line_code], rich_text: hash[:rich_text])
end
def to_hash
@@ -85,7 +86,7 @@ module Gitlab
old_line: old_line,
new_line: new_line,
text: text,
- rich_text: rich_text || text,
+ rich_text: rich_text || CGI.escapeHTML(text),
meta_data: meta_positions
}
end
diff --git a/lib/gitlab/github_import.rb b/lib/gitlab/github_import.rb
index 65b5e30c70f..d40b06f969f 100644
--- a/lib/gitlab/github_import.rb
+++ b/lib/gitlab/github_import.rb
@@ -10,24 +10,6 @@ module Gitlab
Client.new(token_to_use, parallel: parallel)
end
- # Inserts a raw row and returns the ID of the inserted row.
- #
- # attributes - The attributes/columns to set.
- # relation - An ActiveRecord::Relation to use for finding the ID of the row
- # when using MySQL.
- def self.insert_and_return_id(attributes, relation)
- # We use bulk_insert here so we can bypass any queries executed by
- # callbacks or validation rules, as doing this wouldn't scale when
- # importing very large projects.
- result = Gitlab::Database
- .bulk_insert(relation.table_name, [attributes], return_ids: true)
-
- # MySQL doesn't support returning the IDs of a bulk insert in a way that
- # is not a pain, so in this case we'll issue an extra query instead.
- result.first ||
- relation.where(iid: attributes[:iid]).limit(1).pluck(:id).first
- end
-
# Returns the ID of the ghost user.
def self.ghost_user_id
key = 'github-import/ghost-user-id'
diff --git a/lib/gitlab/github_import/importer/issue_importer.rb b/lib/gitlab/github_import/importer/issue_importer.rb
index cb4d7a6a0b6..4226eee85cc 100644
--- a/lib/gitlab/github_import/importer/issue_importer.rb
+++ b/lib/gitlab/github_import/importer/issue_importer.rb
@@ -4,6 +4,8 @@ module Gitlab
module GithubImport
module Importer
class IssueImporter
+ include Gitlab::Import::DatabaseHelpers
+
attr_reader :project, :issue, :client, :user_finder, :milestone_finder,
:issuable_finder
@@ -55,7 +57,7 @@ module Gitlab
updated_at: issue.updated_at
}
- GithubImport.insert_and_return_id(attributes, project.issues).tap do |id|
+ insert_and_return_id(attributes, project.issues).tap do |id|
# We use .insert_and_return_id which effectively disables all callbacks.
# Trigger iid logic here to make sure we track internal id values consistently.
project.issues.find(id).ensure_project_iid!
diff --git a/lib/gitlab/github_import/importer/pull_request_importer.rb b/lib/gitlab/github_import/importer/pull_request_importer.rb
index ed17aa54373..ae7c4cf1b38 100644
--- a/lib/gitlab/github_import/importer/pull_request_importer.rb
+++ b/lib/gitlab/github_import/importer/pull_request_importer.rb
@@ -4,6 +4,8 @@ module Gitlab
module GithubImport
module Importer
class PullRequestImporter
+ include Gitlab::Import::MergeRequestHelpers
+
attr_reader :pull_request, :project, :client, :user_finder,
:milestone_finder, :issuable_finder
@@ -44,81 +46,27 @@ module Gitlab
description = MarkdownText
.format(pull_request.description, pull_request.author, author_found)
- # This work must be wrapped in a transaction as otherwise we can leave
- # behind incomplete data in the event of an error. This can then lead
- # to duplicate key errors when jobs are retried.
- MergeRequest.transaction do
- attributes = {
- iid: pull_request.iid,
- title: pull_request.truncated_title,
- description: description,
- source_project_id: project.id,
- target_project_id: project.id,
- source_branch: pull_request.formatted_source_branch,
- target_branch: pull_request.target_branch,
- state: pull_request.state,
- milestone_id: milestone_finder.id_for(pull_request),
- author_id: author_id,
- assignee_id: user_finder.assignee_id_for(pull_request),
- created_at: pull_request.created_at,
- updated_at: pull_request.updated_at
- }
-
- # When creating merge requests there are a lot of hooks that may
- # run, for many different reasons. Many of these hooks (e.g. the
- # ones used for rendering Markdown) are completely unnecessary and
- # may even lead to transaction timeouts.
- #
- # To ensure importing pull requests has a minimal impact and can
- # complete in a reasonable time we bypass all the hooks by inserting
- # the row and then retrieving it. We then only perform the
- # additional work that is strictly necessary.
- merge_request_id = GithubImport
- .insert_and_return_id(attributes, project.merge_requests)
-
- merge_request = project.merge_requests.find(merge_request_id)
-
- # We use .insert_and_return_id which effectively disables all callbacks.
- # Trigger iid logic here to make sure we track internal id values consistently.
- merge_request.ensure_target_project_iid!
+ attributes = {
+ iid: pull_request.iid,
+ title: pull_request.truncated_title,
+ description: description,
+ source_project_id: project.id,
+ target_project_id: project.id,
+ source_branch: pull_request.formatted_source_branch,
+ target_branch: pull_request.target_branch,
+ state: pull_request.state,
+ milestone_id: milestone_finder.id_for(pull_request),
+ author_id: author_id,
+ assignee_id: user_finder.assignee_id_for(pull_request),
+ created_at: pull_request.created_at,
+ updated_at: pull_request.updated_at
+ }
- [merge_request, false]
- end
- rescue ActiveRecord::InvalidForeignKey
- # It's possible the project has been deleted since scheduling this
- # job. In this case we'll just skip creating the merge request.
- []
- rescue ActiveRecord::RecordNotUnique
- # It's possible we previously created the MR, but failed when updating
- # the Git data. In this case we'll just continue working on the
- # existing row.
- [project.merge_requests.find_by(iid: pull_request.iid), true]
+ create_merge_request_without_hooks(project, attributes, pull_request.iid)
end
- def insert_git_data(merge_request, already_exists = false)
- # These fields are set so we can create the correct merge request
- # diffs.
- merge_request.source_branch_sha = pull_request.source_branch_sha
- merge_request.target_branch_sha = pull_request.target_branch_sha
-
- merge_request.keep_around_commit
-
- # MR diffs normally use an "after_save" hook to pull data from Git.
- # All of this happens in the transaction started by calling
- # create/save/etc. This in turn can lead to these transactions being
- # held open for much longer than necessary. To work around this we
- # first save the diff, then populate it.
- diff =
- if already_exists
- merge_request.merge_request_diffs.take ||
- merge_request.merge_request_diffs.build
- else
- merge_request.merge_request_diffs.build
- end
-
- diff.importing = true
- diff.save
- diff.save_git_content
+ def insert_git_data(merge_request, already_exists)
+ insert_or_replace_git_data(merge_request, pull_request.source_branch_sha, pull_request.target_branch_sha, already_exists)
end
end
end
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index b8213929c6a..7346eab9e76 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -5,6 +5,7 @@ module Gitlab
AVAILABLE_LANGUAGES = {
'en' => 'English',
'es' => 'Español',
+ 'gl_ES' => 'Galego',
'de' => 'Deutsch',
'fr' => 'Français',
'pt_BR' => 'Português (Brasil)',
diff --git a/lib/gitlab/import/database_helpers.rb b/lib/gitlab/import/database_helpers.rb
new file mode 100644
index 00000000000..80857061933
--- /dev/null
+++ b/lib/gitlab/import/database_helpers.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Import
+ module DatabaseHelpers
+ # Inserts a raw row and returns the ID of the inserted row.
+ #
+ # attributes - The attributes/columns to set.
+ # relation - An ActiveRecord::Relation to use for finding the ID of the row
+ # when using MySQL.
+ def insert_and_return_id(attributes, relation)
+ # We use bulk_insert here so we can bypass any queries executed by
+ # callbacks or validation rules, as doing this wouldn't scale when
+ # importing very large projects.
+ result = Gitlab::Database
+ .bulk_insert(relation.table_name, [attributes], return_ids: true)
+
+ # MySQL doesn't support returning the IDs of a bulk insert in a way that
+ # is not a pain, so in this case we'll issue an extra query instead.
+ result.first ||
+ relation.where(iid: attributes[:iid]).limit(1).pluck(:id).first
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import/merge_request_creator.rb b/lib/gitlab/import/merge_request_creator.rb
new file mode 100644
index 00000000000..a01951b0762
--- /dev/null
+++ b/lib/gitlab/import/merge_request_creator.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+# This module is designed for importers that need to create many merge
+# requests quickly. When creating merge requests there are a lot of hooks
+# that may run, for many different reasons. Many of these hooks (e.g. the ones
+# used for rendering Markdown) are completely unnecessary and may even lead to
+# transaction timeouts.
+#
+# To ensure importing merge requests requests has a minimal impact and can
+# complete in a reasonable time we bypass all the hooks by inserting the row
+# and then retrieving it. We then only perform the additional work that is
+# strictly necessary.
+module Gitlab
+ module Import
+ class MergeRequestCreator
+ include ::Gitlab::Import::DatabaseHelpers
+ include ::Gitlab::Import::MergeRequestHelpers
+
+ attr_accessor :project
+
+ def initialize(project)
+ @project = project
+ end
+
+ def execute(attributes)
+ source_branch_sha = attributes.delete(:source_branch_sha)
+ target_branch_sha = attributes.delete(:target_branch_sha)
+ iid = attributes[:iid]
+
+ merge_request, already_exists = create_merge_request_without_hooks(project, attributes, iid)
+
+ if merge_request
+ insert_or_replace_git_data(merge_request, source_branch_sha, target_branch_sha, already_exists)
+ end
+
+ merge_request
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import/merge_request_helpers.rb b/lib/gitlab/import/merge_request_helpers.rb
new file mode 100644
index 00000000000..8ba70700dc1
--- /dev/null
+++ b/lib/gitlab/import/merge_request_helpers.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Import
+ module MergeRequestHelpers
+ include DatabaseHelpers
+
+ def create_merge_request_without_hooks(project, attributes, iid)
+ # This work must be wrapped in a transaction as otherwise we can leave
+ # behind incomplete data in the event of an error. This can then lead
+ # to duplicate key errors when jobs are retried.
+ MergeRequest.transaction do
+ # When creating merge requests there are a lot of hooks that may
+ # run, for many different reasons. Many of these hooks (e.g. the
+ # ones used for rendering Markdown) are completely unnecessary and
+ # may even lead to transaction timeouts.
+ #
+ # To ensure importing pull requests has a minimal impact and can
+ # complete in a reasonable time we bypass all the hooks by inserting
+ # the row and then retrieving it. We then only perform the
+ # additional work that is strictly necessary.
+ merge_request_id = insert_and_return_id(attributes, project.merge_requests)
+
+ merge_request = project.merge_requests.find(merge_request_id)
+
+ # We use .insert_and_return_id which effectively disables all callbacks.
+ # Trigger iid logic here to make sure we track internal id values consistently.
+ merge_request.ensure_target_project_iid!
+
+ [merge_request, false]
+ end
+ rescue ActiveRecord::InvalidForeignKey
+ # It's possible the project has been deleted since scheduling this
+ # job. In this case we'll just skip creating the merge request.
+ []
+ rescue ActiveRecord::RecordNotUnique
+ # It's possible we previously created the MR, but failed when updating
+ # the Git data. In this case we'll just continue working on the
+ # existing row.
+ [project.merge_requests.find_by(iid: iid), true]
+ end
+
+ def insert_or_replace_git_data(merge_request, source_branch_sha, target_branch_sha, already_exists = false)
+ # These fields are set so we can create the correct merge request
+ # diffs.
+ merge_request.source_branch_sha = source_branch_sha
+ merge_request.target_branch_sha = target_branch_sha
+
+ merge_request.keep_around_commit
+
+ # MR diffs normally use an "after_save" hook to pull data from Git.
+ # All of this happens in the transaction started by calling
+ # create/save/etc. This in turn can lead to these transactions being
+ # held open for much longer than necessary. To work around this we
+ # first save the diff, then populate it.
+ diff =
+ if already_exists
+ merge_request.merge_request_diffs.take ||
+ merge_request.merge_request_diffs.build
+ else
+ merge_request.merge_request_diffs.build
+ end
+
+ diff.importing = true
+ diff.save
+ diff.save_git_content
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb
index 07875ebb56a..e0d4235e65b 100644
--- a/lib/gitlab/import_export/uploads_manager.rb
+++ b/lib/gitlab/import_export/uploads_manager.rb
@@ -13,13 +13,11 @@ module Gitlab
end
def save
- copy_files(@from, uploads_export_path) if File.directory?(@from)
-
if File.file?(@from) && @relative_export_path == 'avatar'
copy_files(@from, File.join(uploads_export_path, @project.avatar.filename))
end
- copy_from_object_storage
+ copy_project_uploads
true
rescue => e
@@ -48,14 +46,19 @@ module Gitlab
UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute
end
- def copy_from_object_storage
- return unless Gitlab::ImportExport.object_storage?
-
+ def copy_project_uploads
each_uploader do |uploader|
next unless uploader.file
- next if uploader.upload.local? # Already copied, using the old method
- download_and_copy(uploader)
+ if uploader.upload.local?
+ next unless uploader.upload.exist?
+
+ copy_files(uploader.absolute_path, File.join(uploads_export_path, uploader.upload.path))
+ else
+ next unless Gitlab::ImportExport.object_storage?
+
+ download_and_copy(uploader)
+ end
end
end
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index 18f91db98fc..3d588918adf 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -82,9 +82,13 @@ module Gitlab
end
def open_file(params, key)
- ::UploadedFile.from_params(
- params, key,
- [FileUploader.root, Gitlab.config.uploads.storage_path])
+ allowed_paths = [
+ FileUploader.root,
+ Gitlab.config.uploads.storage_path,
+ File.join(Rails.root, 'public/uploads/tmp')
+ ]
+
+ ::UploadedFile.from_params(params, key, allowed_paths)
end
end
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
index 38be75b7482..3b483f27e70 100644
--- a/lib/gitlab/url_blocker.rb
+++ b/lib/gitlab/url_blocker.rb
@@ -31,6 +31,7 @@ module Gitlab
validate_localhost!(addrs_info) unless allow_localhost
validate_local_network!(addrs_info) unless allow_local_network
+ validate_link_local!(addrs_info) unless allow_local_network
true
end
@@ -89,6 +90,13 @@ module Gitlab
raise BlockedUrlError, "Requests to the local network are not allowed"
end
+ 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) }
+
+ raise BlockedUrlError, "Requests to the link local network are not allowed"
+ end
+
def internal?(uri)
internal_web?(uri) || internal_shell?(uri)
end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 22c9638ecc0..7797bd5fab2 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -34,6 +34,7 @@ module Gitlab
def system_usage_data
{
counts: {
+ assignee_lists: List.assignee.count,
boards: Board.count,
ci_builds: ::Ci::Build.count,
ci_internal_pipelines: ::Ci::Pipeline.internal.count,
@@ -61,9 +62,11 @@ module Gitlab
groups: Group.count,
issues: Issue.count,
keys: Key.count,
+ label_lists: List.label.count,
labels: Label.count,
lfs_objects: LfsObject.count,
merge_requests: MergeRequest.count,
+ milestone_lists: List.milestone.count,
milestones: Milestone.count,
notes: Note.count,
pages_domains: PagesDomain.count,
diff --git a/lib/tasks/gettext.rake b/lib/tasks/gettext.rake
index f431352b61e..a497d26312e 100644
--- a/lib/tasks/gettext.rake
+++ b/lib/tasks/gettext.rake
@@ -82,7 +82,7 @@ namespace :gettext do
# `gettext:find` writes touches to temp files to `stderr` which would cause
# `static-analysis` to report failures. We can ignore these.
- silence_stream($stderr) do
+ silence_sdterr do
Rake::Task['gettext:find'].invoke
end
@@ -118,4 +118,15 @@ namespace :gettext do
end
end
end
+
+ def silence_sdterr(&block)
+ old_stderr = $stderr.dup
+ $stderr.reopen(File::NULL)
+ $stderr.sync = true
+
+ yield
+ ensure
+ $stderr.reopen(old_stderr)
+ old_stderr.close
+ end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f348f66ae17..ce5d82d479b 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2391,6 +2391,18 @@ msgstr ""
msgid "Enter in your Bitbucket Server URL and personal access token below"
msgstr ""
+msgid "Enter the issue description"
+msgstr ""
+
+msgid "Enter the issue title"
+msgstr ""
+
+msgid "Enter the merge request description"
+msgstr ""
+
+msgid "Enter the merge request title"
+msgstr ""
+
msgid "Environments"
msgstr ""
@@ -3620,10 +3632,10 @@ msgstr ""
msgid "Milestones"
msgstr ""
-msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle} from this project and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}. Once deleted, it cannot be undone or recovered."
+msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}. Once deleted, it cannot be undone or recovered."
msgstr ""
-msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle} from this project. %{milestoneTitle} is not currently used in any issues or merge requests."
+msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle}. This milestone is not currently used in any issues or merge requests."
msgstr ""
msgid "Milestones|Delete milestone"
@@ -5050,6 +5062,9 @@ msgstr ""
msgid "Settings"
msgstr ""
+msgid "Setup a %{type} Runner manually"
+msgstr ""
+
msgid "Setup a specific Runner automatically"
msgstr ""
@@ -5477,6 +5492,9 @@ msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
+msgid "The deployment of this job to %{environmentLink} did not succeed."
+msgstr ""
+
msgid "The fork relationship has been removed."
msgstr ""
@@ -5552,6 +5570,9 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
+msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
+msgstr ""
+
msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of <code>:</code>. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side."
msgstr ""
@@ -5657,6 +5678,18 @@ msgstr ""
msgid "This job has not started yet"
msgstr ""
+msgid "This job is an out-of-date deployment to %{environmentLink}."
+msgstr ""
+
+msgid "This job is an out-of-date deployment to %{environmentLink}. View the most recent deployment %{deploymentLink}."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink} and will overwrite the last %{deploymentLink}."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink}."
+msgstr ""
+
msgid "This job is in pending state and is waiting to be picked by a runner"
msgstr ""
@@ -5666,6 +5699,9 @@ msgstr ""
msgid "This job is stuck, because you don't have any active runners that can run this job."
msgstr ""
+msgid "This job is the most recent deployment to %{link}."
+msgstr ""
+
msgid "This job requires a manual action"
msgstr ""
@@ -6706,6 +6742,9 @@ msgstr ""
msgid "mrWidget|The source branch has been removed"
msgstr ""
+msgid "mrWidget|The source branch is %{commitsBehindLinkStart}%{commitsBehind}%{commitsBehindLinkEnd} the target branch"
+msgstr ""
+
msgid "mrWidget|The source branch is being removed"
msgstr ""
diff --git a/qa/qa.rb b/qa/qa.rb
index 4b927067449..cf15a8b229c 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -83,6 +83,7 @@ module QA
# Test scenario entrypoints.
#
module Test
+ autoload :Instance, 'qa/scenario/test/instance'
module Instance
autoload :All, 'qa/scenario/test/instance/all'
autoload :Smoke, 'qa/scenario/test/instance/smoke'
diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb
index 36567927194..1a410a0f8a5 100644
--- a/qa/qa/page/project/import/github.rb
+++ b/qa/qa/page/project/import/github.rb
@@ -14,7 +14,7 @@ module QA
element :project_import_row, 'data: { qa: { repo_path: repo.full_name } }'
element :project_namespace_select
element :project_namespace_field, 'select_tag :namespace_id'
- element :project_path_field, 'text_field_tag :path, repo.name'
+ element :project_path_field, 'text_field_tag :path, sanitize_project_name(repo.name)'
element :import_button, "_('Import')"
end
diff --git a/qa/qa/scenario/template.rb b/qa/qa/scenario/template.rb
index 66eb86f25c8..a87d925ce32 100644
--- a/qa/qa/scenario/template.rb
+++ b/qa/qa/scenario/template.rb
@@ -21,14 +21,18 @@ module QA
def perform(address, *rspec_options)
Runtime::Scenario.define(:gitlab_address, address)
+ ##
+ # Perform before hooks, which are different for CE and EE
+ #
+ Runtime::Release.perform_before_hooks
+
Specs::Runner.perform do |specs|
specs.tty = true
- specs.tags = self.class.focus
specs.options =
if rspec_options.any?
rspec_options
else
- ::File.expand_path('../specs/features', __dir__)
+ ['--tag', self.class.focus.join(','), '--', ::File.expand_path('../specs/features', __dir__)]
end
end
end
diff --git a/qa/qa/scenario/test/instance.rb b/qa/qa/scenario/test/instance.rb
new file mode 100644
index 00000000000..a2d503cc015
--- /dev/null
+++ b/qa/qa/scenario/test/instance.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Scenario
+ module Test
+ # This class exists for back-compatibility so that gitlab-qa can continue
+ # to call Test::Instance instead of Test::Instance::All until at least
+ # the current latest GitLab version has the Test::Instance::All class.
+ # As of Aug, 22nd 2018. Only GitLab >= 11.3 has this class.
+ module Instance
+ include Bootable
+
+ def self.perform(*args)
+ self.tap do |scenario|
+ yield scenario if block_given?
+ break scenario.do_perform(*args)
+ end
+ end
+
+ def self.do_perform(address, *rspec_options)
+ Runtime::Scenario.define(:gitlab_address, address)
+
+ ##
+ # Perform before hooks, which are different for CE and EE
+ #
+ Runtime::Release.perform_before_hooks
+
+ Specs::Runner.perform do |specs|
+ specs.tty = true
+ specs.options =
+ if rspec_options.any?
+ rspec_options
+ else
+ ['--', ::File.expand_path('../../specs/features', __dir__)]
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/1_manage/.gitkeep b/qa/qa/specs/features/api/1_manage/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/api/1_manage/.gitkeep
diff --git a/qa/qa/specs/features/api/users_spec.rb b/qa/qa/specs/features/api/1_manage/users_spec.rb
index 3d25cca1e59..3e3c9e859aa 100644
--- a/qa/qa/specs/features/api/users_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/users_spec.rb
@@ -1,19 +1,21 @@
+# frozen_string_literal: true
+
module QA
- describe 'API users' do
- before(:context) do
- @api_client = Runtime::API::Client.new(:gitlab)
- end
+ context :manage do
+ describe 'Users API' do
+ before(:context) do
+ @api_client = Runtime::API::Client.new(:gitlab)
+ end
- context 'when authenticated' do
let(:request) { Runtime::API::Request.new(@api_client, '/users') }
- it 'get list of users' do
+ it 'GET /users' do
get request.url
expect_status(200)
end
- it 'submit request with a valid user name' do
+ it 'GET /users/:username with a valid username' do
get request.url, { params: { username: Runtime::User.username } }
expect_status(200)
@@ -22,20 +24,12 @@ module QA
)
end
- it 'submit request with an invalid user name' do
+ it 'GET /users/:username with an invalid username' do
get request.url, { params: { username: SecureRandom.hex(10) } }
expect_status(200)
expect(json_body).to eq([])
end
end
-
- it 'submit request with an invalid token' do
- request = Runtime::API::Request.new(@api_client, '/users', private_token: 'invalid')
-
- get request.url
-
- expect_status(401)
- end
end
end
diff --git a/qa/qa/specs/features/api/2_plan/.gitkeep b/qa/qa/specs/features/api/2_plan/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/api/2_plan/.gitkeep
diff --git a/qa/qa/specs/features/api/basics_spec.rb b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
index bc0b5ebfe10..bc0b5ebfe10 100644
--- a/qa/qa/specs/features/api/basics_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
diff --git a/qa/qa/specs/features/api/4_verify/.gitkeep b/qa/qa/specs/features/api/4_verify/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/api/4_verify/.gitkeep
diff --git a/qa/qa/specs/features/api/5_package/.gitkeep b/qa/qa/specs/features/api/5_package/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/api/5_package/.gitkeep
diff --git a/qa/qa/specs/features/api/6_release/.gitkeep b/qa/qa/specs/features/api/6_release/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/api/6_release/.gitkeep
diff --git a/qa/qa/specs/features/api/7_configure/.gitkeep b/qa/qa/specs/features/api/7_configure/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/api/7_configure/.gitkeep
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
new file mode 100644
index 00000000000..1c7da930567
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
@@ -0,0 +1,17 @@
+module QA
+ context :manage, :smoke do
+ describe 'basic user login' do
+ it 'user logs in using basic credentials' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ # TODO, since `Signed in successfully` message was removed
+ # this is the only way to tell if user is signed in correctly.
+ #
+ Page::Menu::Main.perform do |menu|
+ expect(menu).to have_personal_area
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
new file mode 100644
index 00000000000..c9958917be9
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ context :manage, :orchestrated, :ldap do
+ describe 'LDAP login' do
+ before do
+ Runtime::Env.user_type = 'ldap'
+ end
+
+ it 'user logs into GitLab using LDAP credentials' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ # TODO, since `Signed in successfully` message was removed
+ # this is the only way to tell if user is signed in correctly.
+ #
+ Page::Menu::Main.perform do |menu|
+ expect(menu).to have_personal_area
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
new file mode 100644
index 00000000000..6eda2c750d4
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ context :manage, :orchestrated, :mattermost do
+ describe 'Mattermost login' do
+ it 'user logs into Mattermost using GitLab OAuth' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login) do
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ Runtime::Browser.visit(:mattermost, Page::Mattermost::Login) do
+ Page::Mattermost::Login.act { sign_in_using_oauth }
+
+ Page::Mattermost::Main.perform do |page|
+ expect(page).to have_content(/(Welcome to: Mattermost|Logout GitLab Mattermost)/)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
new file mode 100644
index 00000000000..bb1f3ab26d1
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module QA
+ context :manage, :smoke do
+ describe 'Project creation' do
+ it 'user creates a new project' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ created_project = Factory::Resource::Project.fabricate! do |project|
+ project.name = 'awesome-project'
+ project.description = 'create awesome project test'
+ end
+
+ expect(created_project.name).to match /^awesome-project-\h{16}$/
+
+ expect(page).to have_content(
+ /Project \S?awesome-project\S+ was successfully created/
+ )
+
+ expect(page).to have_content('create awesome project test')
+ expect(page).to have_content('The repository for this project is empty')
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
new file mode 100644
index 00000000000..2ef8de61441
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+module QA
+ context :manage, :orchestrated, :github do
+ describe 'Project import from GitHub' do
+ let(:imported_project) do
+ Factory::Resource::ProjectImportedFromGithub.fabricate! do |project|
+ project.name = 'imported-project'
+ project.personal_access_token = Runtime::Env.github_access_token
+ project.github_repository_path = 'gitlab-qa/test-project'
+ end
+ end
+
+ after do
+ # We need to delete the imported project because it's impossible to import
+ # the same GitHub project twice for a given user.
+ api_client = Runtime::API::Client.new(:gitlab)
+ delete_project_request = Runtime::API::Request.new(api_client, "/projects/#{CGI.escape("#{Runtime::Namespace.path}/#{imported_project.name}")}")
+ delete delete_project_request.url
+
+ expect_status(202)
+ end
+
+ it 'user imports a GitHub repo' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ imported_project # import the project
+
+ Page::Menu::Main.act { go_to_projects }
+ Page::Dashboard::Projects.perform do |dashboard|
+ dashboard.go_to_project(imported_project.name)
+ end
+
+ Page::Project::Show.act { wait_for_import }
+
+ verify_repository_import
+ verify_issues_import
+ verify_merge_requests_import
+ verify_labels_import
+ verify_milestones_import
+ verify_wiki_import
+ end
+
+ def verify_repository_import
+ expect(page).to have_content('This test project is used for automated GitHub import by GitLab QA.')
+ expect(page).to have_content(imported_project.name)
+ end
+
+ def verify_issues_import
+ Page::Menu::Side.act { click_issues }
+ expect(page).to have_content('This is a sample issue')
+
+ click_link 'This is a sample issue'
+
+ expect(page).to have_content('We should populate this project with issues, pull requests and wiki pages.')
+
+ # Comments
+ expect(page).to have_content('This is a comment from @rymai.')
+
+ Page::Issuable::Sidebar.perform do |issuable|
+ expect(issuable).to have_label('enhancement')
+ expect(issuable).to have_label('help wanted')
+ expect(issuable).to have_label('good first issue')
+ end
+ end
+
+ def verify_merge_requests_import
+ Page::Menu::Side.act { click_merge_requests }
+ expect(page).to have_content('Improve README.md')
+
+ click_link 'Improve README.md'
+
+ expect(page).to have_content('This improves the README file a bit.')
+
+ # Review comment are not supported yet
+ expect(page).not_to have_content('Really nice change.')
+
+ # Comments
+ expect(page).to have_content('Nice work! This is a comment from @rymai.')
+
+ # Diff comments
+ expect(page).to have_content('[Review comment] I like that!')
+ expect(page).to have_content('[Review comment] Nice blank line.')
+ expect(page).to have_content('[Single diff comment] Much better without this line!')
+
+ Page::Issuable::Sidebar.perform do |issuable|
+ expect(issuable).to have_label('bug')
+ expect(issuable).to have_label('enhancement')
+ end
+ end
+
+ def verify_labels_import
+ # TODO: Waiting on https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/19228
+ # to build upon it.
+ end
+
+ def verify_milestones_import
+ # TODO: Waiting on https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18727
+ # to build upon it.
+ end
+
+ def verify_wiki_import
+ Page::Menu::Side.act { click_wiki }
+
+ expect(page).to have_content('Welcome to the test-project wiki!')
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb
new file mode 100644
index 00000000000..34bb6f1c197
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module QA
+ context :manage do
+ describe 'Project activity' do
+ it 'user creates an event in the activity page upon Git push' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ Factory::Repository::ProjectPush.fabricate! do |push|
+ push.file_name = 'README.md'
+ push.file_content = '# This is a test project'
+ push.commit_message = 'Add README.md'
+ end
+
+ Page::Menu::Side.act { go_to_activity }
+
+ Page::Project::Activity.act { go_to_push_events }
+
+ expect(page).to have_content('pushed new branch master')
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
new file mode 100644
index 00000000000..dd1be935220
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module QA
+ context :plan, :smoke do
+ describe 'Issue creation' do
+ let(:issue_title) { 'issue title' }
+
+ it 'user creates an issue' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ Factory::Resource::Issue.fabricate! do |issue|
+ issue.title = issue_title
+ end
+
+ Page::Menu::Side.act { click_issues }
+
+ expect(page).to have_content(issue_title)
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
new file mode 100644
index 00000000000..bcf55a02a61
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'Merge request creation' do
+ it 'user creates a new merge request' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ current_project = Factory::Resource::Project.fabricate! do |project|
+ project.name = 'project-with-merge-request-and-milestone'
+ end
+
+ current_milestone = Factory::Resource::ProjectMilestone.fabricate! do |milestone|
+ milestone.title = 'unique-milestone'
+ milestone.project = current_project
+ end
+
+ Factory::Resource::MergeRequest.fabricate! do |merge_request|
+ merge_request.title = 'This is a merge request with a milestone'
+ merge_request.description = 'Great feature with milestone'
+ merge_request.project = current_project
+ merge_request.milestone = current_milestone
+ end
+
+ expect(page).to have_content('This is a merge request with a milestone')
+ expect(page).to have_content('Great feature with milestone')
+ expect(page).to have_content(/Opened [\w\s]+ ago/)
+
+ Page::Issuable::Sidebar.perform do |sidebar|
+ expect(sidebar).to have_milestone(current_milestone.title)
+ end
+ end
+ end
+ end
+
+ describe 'creates a merge request', :smoke do
+ it 'user creates a new merge request' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ current_project = Factory::Resource::Project.fabricate! do |project|
+ project.name = 'project-with-merge-request'
+ end
+
+ Factory::Resource::MergeRequest.fabricate! do |merge_request|
+ merge_request.title = 'This is a merge request'
+ merge_request.description = 'Great feature'
+ merge_request.project = current_project
+ end
+
+ expect(page).to have_content('This is a merge request')
+ expect(page).to have_content('Great feature')
+ expect(page).to have_content(/Opened [\w\s]+ ago/)
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
new file mode 100644
index 00000000000..407a15800ab
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'Merge request creation from fork' do
+ it 'user forks a project, submits a merge request and maintainer merges it' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ merge_request = Factory::Resource::MergeRequestFromFork.fabricate! do |merge_request|
+ merge_request.fork_branch = 'feature-branch'
+ end
+
+ Page::Menu::Main.perform { |main| main.sign_out }
+ Page::Main::Login.perform { |login| login.sign_in_using_credentials }
+
+ merge_request.visit!
+
+ Page::MergeRequest::Show.perform { |show| show.merge! }
+
+ expect(page).to have_content('The changes were merged')
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
new file mode 100644
index 00000000000..ddcbc94b1b1
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'Merge request rebasing' do
+ it 'user rebases source branch of merge request' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ project = Factory::Resource::Project.fabricate! do |project|
+ project.name = "only-fast-forward"
+ end
+
+ Page::Menu::Side.act { go_to_settings }
+ Page::Project::Settings::MergeRequest.act { enable_ff_only }
+
+ merge_request = Factory::Resource::MergeRequest.fabricate! do |merge_request|
+ merge_request.project = project
+ merge_request.title = 'Needs rebasing'
+ end
+
+ Factory::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.file_name = "other.txt"
+ push.file_content = "New file added!"
+ push.branch_name = "master"
+ push.new_branch = false
+ end
+
+ merge_request.visit!
+
+ Page::MergeRequest::Show.perform do |merge_request|
+ expect(merge_request).to have_content('Needs rebasing')
+ expect(merge_request).not_to be_fast_forward_possible
+ expect(merge_request).not_to have_merge_button
+
+ merge_request.rebase!
+
+ expect(merge_request).to have_merge_button
+ expect(merge_request.fast_forward_possible?).to be_truthy
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
new file mode 100644
index 00000000000..b5b8855a35d
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'Merge request squashing' do
+ it 'user squashes commits while merging' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ project = Factory::Resource::Project.fabricate! do |project|
+ project.name = "squash-before-merge"
+ end
+
+ merge_request = Factory::Resource::MergeRequest.fabricate! do |merge_request|
+ merge_request.project = project
+ merge_request.title = 'Squashing commits'
+ end
+
+ Factory::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.commit_message = 'to be squashed'
+ push.branch_name = merge_request.source_branch
+ push.new_branch = false
+ push.file_name = 'other.txt'
+ push.file_content = "Test with unicode characters ❤✓€❄"
+ end
+
+ merge_request.visit!
+
+ expect(page).to have_text('to be squashed')
+
+ Page::MergeRequest::Show.perform do |merge_request_page|
+ merge_request_page.mark_to_squash
+ merge_request_page.merge!
+
+ merge_request.project.visit!
+
+ Git::Repository.perform do |repository|
+ repository.uri = Page::Project::Show.act do
+ choose_repository_clone_http
+ repository_location.uri
+ end
+
+ repository.use_default_credentials
+
+ repository.act { clone }
+
+ expect(repository.commits.size).to eq 3
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/repository/clone_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb
index 70881f0f8d1..0dcdc6639d1 100644
--- a/qa/qa/specs/features/repository/clone_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb
@@ -1,6 +1,8 @@
+# frozen_string_literal: true
+
module QA
- describe 'clone code from the repository', :ldap do
- context 'with regular account over http' do
+ context :create do
+ describe 'Git clone over HTTP', :ldap do
let(:location) do
Page::Project::Show.act do
choose_repository_clone_http
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
new file mode 100644
index 00000000000..f18655442c1
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module QA
+ context :create, :core do
+ describe 'Files management' do
+ it 'user creates, edits and deletes a file via the Web' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ # Create
+ file_name = 'QA Test - File name'
+ file_content = 'QA Test - File content'
+ commit_message_for_create = 'QA Test - Create new file'
+
+ Factory::Resource::File.fabricate! do |file|
+ file.name = file_name
+ file.content = file_content
+ file.commit_message = commit_message_for_create
+ end
+
+ expect(page).to have_content('The file has been successfully created.')
+ expect(page).to have_content(file_name)
+ expect(page).to have_content(file_content)
+ expect(page).to have_content(commit_message_for_create)
+
+ # Edit
+ updated_file_content = 'QA Test - Updated file content'
+ commit_message_for_update = 'QA Test - Update file'
+
+ Page::File::Show.act { click_edit }
+
+ Page::File::Form.act do
+ remove_content
+ add_content(updated_file_content)
+ add_commit_message(commit_message_for_update)
+ commit_changes
+ end
+
+ expect(page).to have_content('Your changes have been successfully committed.')
+ expect(page).to have_content(updated_file_content)
+ expect(page).to have_content(commit_message_for_update)
+
+ # Delete
+ commit_message_for_delete = 'QA Test - Delete file'
+
+ Page::File::Show.act do
+ click_delete
+ add_commit_message(commit_message_for_delete)
+ click_delete_file
+ end
+
+ expect(page).to have_content('The file has been successfully deleted.')
+ expect(page).to have_content(commit_message_for_delete)
+ expect(page).to have_no_content(file_name)
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/repository/push_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
index 99d4c16c7c7..bf32569b6cb 100644
--- a/qa/qa/specs/features/repository/push_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
@@ -1,6 +1,8 @@
+# frozen_string_literal: true
+
module QA
- describe 'push code to repository', :ldap do
- context 'with regular account over http' do
+ context :create do
+ describe 'Git push over HTTP', :ldap do
it 'user pushes code to the repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
new file mode 100644
index 00000000000..b2da685c477
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'Protected branch support', :ldap do
+ let(:branch_name) { 'protected-branch' }
+ let(:commit_message) { 'Protected push commit message' }
+ let(:project) do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'protected-branch-project'
+ end
+ end
+
+ before do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+ end
+
+ after do
+ # We need to clear localStorage because we're using it for the dropdown,
+ # and capybara doesn't do this for us.
+ # https://github.com/teamcapybara/capybara/issues/1702
+ Capybara.execute_script 'localStorage.clear()'
+ end
+
+ context 'when developers and maintainers are allowed to push to a protected branch' do
+ it 'user with push rights successfully pushes to the protected branch' do
+ create_protected_branch(allow_to_push: true)
+
+ push = push_new_file(branch_name)
+
+ expect(push.output).to match(/remote: To create a merge request for protected-branch, visit/)
+ end
+ end
+
+ context 'when developers and maintainers are not allowed to push to a protected branch' do
+ it 'user without push rights fails to push to the protected branch' do
+ create_protected_branch(allow_to_push: false)
+
+ push = push_new_file(branch_name)
+
+ expect(push.output)
+ .to match(/remote\: GitLab\: You are not allowed to push code to protected branches on this project/)
+ expect(push.output)
+ .to match(/\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/)
+ end
+ end
+
+ def create_protected_branch(allow_to_push:)
+ Factory::Resource::Branch.fabricate! do |resource|
+ resource.branch_name = branch_name
+ resource.project = project
+ resource.allow_to_push = allow_to_push
+ resource.protected = true
+ end
+ end
+
+ def push_new_file(branch)
+ Factory::Repository::ProjectPush.fabricate! do |resource|
+ resource.project = project
+ resource.file_name = 'new_file.md'
+ resource.file_content = '# This is a new file'
+ resource.commit_message = 'Add new_file.md'
+ resource.branch_name = branch_name
+ resource.new_branch = false
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
new file mode 100644
index 00000000000..8009b9e8609
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'Wiki management' do
+ def login
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+ end
+
+ def validate_content(content)
+ expect(page).to have_content('Wiki was successfully updated')
+ expect(page).to have_content(/#{content}/)
+ end
+
+ before do
+ login
+ end
+
+ it 'user creates, edits, clones, and pushes to the wiki' do
+ wiki = Factory::Resource::Wiki.fabricate! do |resource|
+ resource.title = 'Home'
+ resource.content = '# My First Wiki Content'
+ resource.message = 'Update home'
+ end
+
+ validate_content('My First Wiki Content')
+
+ Page::Project::Wiki::Edit.act { go_to_edit_page }
+ Page::Project::Wiki::New.perform do |page|
+ page.set_content("My Second Wiki Content")
+ page.save_changes
+ end
+
+ validate_content('My Second Wiki Content')
+
+ Factory::Repository::WikiPush.fabricate! do |push|
+ push.wiki = wiki
+ push.file_name = 'Home.md'
+ push.file_content = '# My Third Wiki Content'
+ push.commit_message = 'Update Home.md'
+ end
+ Page::Menu::Side.act { click_wiki }
+
+ expect(page).to have_content('My Third Wiki Content')
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
new file mode 100644
index 00000000000..cdfe9b90e15
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+module QA
+ context :verify, :orchestrated, :docker do
+ describe 'Pipeline creation and processing' do
+ let(:executor) { "qa-runner-#{Time.now.to_i}" }
+
+ after do
+ Service::Runner.new(executor).remove!
+ end
+
+ it 'users creates a pipeline which gets processed' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ project = Factory::Resource::Project.fabricate! do |project|
+ project.name = 'project-with-pipelines'
+ project.description = 'Project with CI/CD Pipelines.'
+ end
+
+ Factory::Resource::Runner.fabricate! do |runner|
+ runner.project = project
+ runner.name = executor
+ runner.tags = %w[qa test]
+ end
+
+ Factory::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.file_name = '.gitlab-ci.yml'
+ push.commit_message = 'Add .gitlab-ci.yml'
+ push.file_content = <<~EOF
+ test-success:
+ tags:
+ - qa
+ - test
+ script: echo 'OK'
+
+ test-failure:
+ tags:
+ - qa
+ - test
+ script:
+ - echo 'FAILURE'
+ - exit 1
+
+ test-tags:
+ tags:
+ - qa
+ - docker
+ script: echo 'NOOP'
+
+ test-artifacts:
+ tags:
+ - qa
+ - test
+ script: mkdir my-artifacts; echo "CONTENTS" > my-artifacts/artifact.txt
+ artifacts:
+ paths:
+ - my-artifacts/
+ EOF
+ end
+
+ Page::Project::Show.act { wait_for_push }
+
+ expect(page).to have_content('Add .gitlab-ci.yml')
+
+ Page::Menu::Side.act { click_ci_cd_pipelines }
+
+ expect(page).to have_content('All 1')
+ expect(page).to have_content('Add .gitlab-ci.yml')
+
+ puts 'Waiting for the runner to process the pipeline'
+ sleep 15 # Runner should process all jobs within 15 seconds.
+
+ Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ expect(pipeline).to be_running
+ expect(pipeline).to have_build('test-success', status: :success)
+ expect(pipeline).to have_build('test-failure', status: :failed)
+ expect(pipeline).to have_build('test-tags', status: :pending)
+ expect(pipeline).to have_build('test-artifacts', status: :success)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
new file mode 100644
index 00000000000..8d83a20f5bf
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module QA
+ context :verify, :docker do
+ describe 'Runner registration' do
+ let(:executor) { "qa-runner-#{Time.now.to_i}" }
+
+ after do
+ Service::Runner.new(executor).remove!
+ end
+
+ it 'user registers a new specific runner' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ Factory::Resource::Runner.fabricate! do |runner|
+ runner.name = executor
+ end
+
+ Page::Project::Settings::CICD.perform do |settings|
+ sleep 5 # Runner should register within 5 seconds
+ settings.refresh
+
+ settings.expand_runners_settings do |page|
+ expect(page).to have_content(executor)
+ expect(page).to have_online_runner
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/secret_variable/add_secret_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/secret_variable/add_secret_variable_spec.rb
new file mode 100644
index 00000000000..08a87df5837
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/secret_variable/add_secret_variable_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module QA
+ context :verify do
+ describe 'Secret variable support' do
+ it 'user adds a secret variable' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ Factory::Resource::SecretVariable.fabricate! do |resource|
+ resource.key = 'VARIABLE_KEY'
+ resource.value = 'some secret variable'
+ end
+
+ Page::Project::Settings::CICD.perform do |settings|
+ settings.expand_secret_variables do |page|
+ expect(page).to have_field(with: 'VARIABLE_KEY')
+ expect(page).not_to have_field(with: 'some secret variable')
+
+ page.reveal_variables
+
+ expect(page).to have_field(with: 'some secret variable')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/5_package/.gitkeep b/qa/qa/specs/features/browser_ui/5_package/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/5_package/.gitkeep
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
new file mode 100644
index 00000000000..17dfa887434
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ context :release do
+ describe 'Deploy key creation' do
+ it 'user adds a deploy key' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ key = Runtime::Key::RSA.new
+ deploy_key_title = 'deploy key title'
+ deploy_key_value = key.public_key
+
+ deploy_key = Factory::Resource::DeployKey.fabricate! do |resource|
+ resource.title = deploy_key_title
+ resource.key = deploy_key_value
+ end
+
+ expect(deploy_key.fingerprint).to eq(key.fingerprint)
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
new file mode 100644
index 00000000000..8352d13b06d
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'digest/sha1'
+
+module QA
+ context :release, :docker do
+ describe 'Git clone using a deploy key' do
+ def login
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+ end
+
+ before(:all) do
+ login
+
+ @runner_name = "qa-runner-#{Time.now.to_i}"
+
+ @project = Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'deploy-key-clone-project'
+ end
+
+ @repository_location = @project.repository_ssh_location
+
+ Factory::Resource::Runner.fabricate! do |resource|
+ resource.project = @project
+ resource.name = @runner_name
+ resource.tags = %w[qa docker]
+ resource.image = 'gitlab/gitlab-runner:ubuntu'
+ end
+
+ Page::Menu::Main.act { sign_out }
+ end
+
+ after(:all) do
+ Service::Runner.new(@runner_name).remove!
+ end
+
+ keys = [
+ [Runtime::Key::RSA, 8192],
+ [Runtime::Key::ECDSA, 521],
+ [Runtime::Key::ED25519]
+ ]
+
+ keys.each do |(key_class, bits)|
+ it "user sets up a deploy key with #{key_class}(#{bits}) to clone code using pipelines" do
+ key = key_class.new(*bits)
+
+ login
+
+ Factory::Resource::DeployKey.fabricate! do |resource|
+ resource.project = @project
+ resource.title = "deploy key #{key.name}(#{key.bits})"
+ resource.key = key.public_key
+ end
+
+ deploy_key_name = "DEPLOY_KEY_#{key.name}_#{key.bits}"
+
+ Factory::Resource::SecretVariable.fabricate! do |resource|
+ resource.project = @project
+ resource.key = deploy_key_name
+ resource.value = key.private_key
+ end
+
+ gitlab_ci = <<~YAML
+ cat-config:
+ script:
+ - mkdir -p ~/.ssh
+ - ssh-keyscan -p #{@repository_location.port} #{@repository_location.host} >> ~/.ssh/known_hosts
+ - eval $(ssh-agent -s)
+ - ssh-add -D
+ - echo "$#{deploy_key_name}" | ssh-add -
+ - git clone #{@repository_location.git_uri}
+ - cd #{@project.name}
+ - git checkout #{deploy_key_name}
+ - sha1sum .gitlab-ci.yml
+ tags:
+ - qa
+ - docker
+ YAML
+
+ Factory::Repository::ProjectPush.fabricate! do |resource|
+ resource.project = @project
+ resource.file_name = '.gitlab-ci.yml'
+ resource.commit_message = 'Add .gitlab-ci.yml'
+ resource.file_content = gitlab_ci
+ resource.branch_name = deploy_key_name
+ resource.new_branch = true
+ end
+
+ sha1sum = Digest::SHA1.hexdigest(gitlab_ci)
+
+ Page::Project::Show.act { wait_for_push }
+ Page::Menu::Side.act { click_ci_cd_pipelines }
+ Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
+ Page::Project::Pipeline::Show.act { go_to_first_job }
+
+ Page::Project::Job::Show.perform do |job|
+ job.wait(reload: false) do
+ job.completed? && !job.trace_loading?
+ end
+
+ expect(job.passed?).to be_truthy, "Job status did not become \"passed\"."
+ expect(job.output).to include(sha1sum)
+ end
+ end
+ end
+ end
+ end
+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
new file mode 100644
index 00000000000..dd24e8ffba5
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'pathname'
+
+module QA
+ context :configure, :orchestrated, :kubernetes do
+ describe 'Auto DevOps support' do
+ after do
+ @cluster&.remove!
+ end
+
+ it 'user creates a new project and runs auto devops' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ project = Factory::Resource::Project.fabricate! do |p|
+ p.name = 'project-with-autodevops'
+ p.description = 'Project with Auto Devops'
+ end
+
+ # Disable code_quality check in Auto DevOps pipeline as it takes
+ # too long and times out the test
+ Factory::Resource::SecretVariable.fabricate! do |resource|
+ resource.key = 'CODE_QUALITY_DISABLED'
+ resource.value = '1'
+ end
+
+ # Create Auto Devops compatible repo
+ Factory::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.directory = Pathname
+ .new(__dir__)
+ .join('../../../fixtures/auto_devops_rack')
+ push.commit_message = 'Create Auto DevOps compatible rack application'
+ end
+
+ Page::Project::Show.act { wait_for_push }
+
+ # Create and connect K8s cluster
+ @cluster = Service::KubernetesCluster.new.create!
+ kubernetes_cluster = Factory::Resource::KubernetesCluster.fabricate! do |cluster|
+ cluster.project = project
+ cluster.cluster = @cluster
+ cluster.install_helm_tiller = true
+ cluster.install_ingress = true
+ cluster.install_prometheus = true
+ cluster.install_runner = true
+ end
+
+ project.visit!
+ Page::Menu::Side.act { click_ci_cd_settings }
+ Page::Project::Settings::CICD.perform do |p|
+ p.enable_auto_devops_with_domain("#{kubernetes_cluster.ingress_ip}.nip.io")
+ end
+
+ project.visit!
+ Page::Menu::Side.act { click_ci_cd_pipelines }
+ Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ expect(pipeline).to have_build('build', status: :success, wait: 600)
+ expect(pipeline).to have_build('test', status: :success, wait: 600)
+ expect(pipeline).to have_build('production', status: :success, wait: 1200)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb
new file mode 100644
index 00000000000..6ffdc55538a
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ context :configure, :orchestrated, :mattermost do
+ describe 'Mattermost support' do
+ it 'user creates a group with a mattermost team' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+ Page::Menu::Main.act { go_to_groups }
+
+ Page::Dashboard::Groups.perform do |page|
+ page.go_to_new_group
+
+ expect(page).to have_content(
+ /Create a Mattermost team for this group/
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/login/basic_spec.rb b/qa/qa/specs/features/login/basic_spec.rb
deleted file mode 100644
index f866466c7bf..00000000000
--- a/qa/qa/specs/features/login/basic_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-module QA
- describe 'basic user login', :smoke do
- it 'user logs in using basic credentials' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- # TODO, since `Signed in successfully` message was removed
- # this is the only way to tell if user is signed in correctly.
- #
- Page::Menu::Main.perform do |menu|
- expect(menu).to have_personal_area
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/login/ldap_spec.rb b/qa/qa/specs/features/login/ldap_spec.rb
deleted file mode 100644
index de6111eea64..00000000000
--- a/qa/qa/specs/features/login/ldap_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module QA
- describe 'LDAP user login', :orchestrated, :ldap do
- before do
- Runtime::Env.user_type = 'ldap'
- end
-
- it 'user logs in using LDAP credentials' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- # TODO, since `Signed in successfully` message was removed
- # this is the only way to tell if user is signed in correctly.
- #
- Page::Menu::Main.perform do |menu|
- expect(menu).to have_personal_area
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/mattermost/group_create_spec.rb b/qa/qa/specs/features/mattermost/group_create_spec.rb
deleted file mode 100644
index 097e1713aef..00000000000
--- a/qa/qa/specs/features/mattermost/group_create_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module QA
- describe 'create a new group', :orchestrated, :mattermost do
- it 'creating a group with a mattermost team' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
- Page::Menu::Main.act { go_to_groups }
-
- Page::Dashboard::Groups.perform do |page|
- page.go_to_new_group
-
- expect(page).to have_content(
- /Create a Mattermost team for this group/
- )
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/mattermost/login_spec.rb b/qa/qa/specs/features/mattermost/login_spec.rb
deleted file mode 100644
index 27f7d4c245f..00000000000
--- a/qa/qa/specs/features/mattermost/login_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module QA
- describe 'logging in to Mattermost', :orchestrated, :mattermost do
- it 'can use gitlab oauth' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login) do
- Page::Main::Login.act { sign_in_using_credentials }
-
- Runtime::Browser.visit(:mattermost, Page::Mattermost::Login) do
- Page::Mattermost::Login.act { sign_in_using_oauth }
-
- Page::Mattermost::Main.perform do |page|
- expect(page).to have_content(/(Welcome to: Mattermost|Logout GitLab Mattermost)/)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/merge_request/create_spec.rb b/qa/qa/specs/features/merge_request/create_spec.rb
deleted file mode 100644
index 71e79956b85..00000000000
--- a/qa/qa/specs/features/merge_request/create_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-module QA
- describe 'creates a merge request with milestone' do
- it 'user creates a new merge request' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- current_project = Factory::Resource::Project.fabricate! do |project|
- project.name = 'project-with-merge-request-and-milestone'
- end
-
- current_milestone = Factory::Resource::ProjectMilestone.fabricate! do |milestone|
- milestone.title = 'unique-milestone'
- milestone.project = current_project
- end
-
- Factory::Resource::MergeRequest.fabricate! do |merge_request|
- merge_request.title = 'This is a merge request with a milestone'
- merge_request.description = 'Great feature with milestone'
- merge_request.project = current_project
- merge_request.milestone = current_milestone
- end
-
- expect(page).to have_content('This is a merge request with a milestone')
- expect(page).to have_content('Great feature with milestone')
- expect(page).to have_content(/Opened [\w\s]+ ago/)
-
- Page::Issuable::Sidebar.perform do |sidebar|
- expect(sidebar).to have_milestone(current_milestone.title)
- end
- end
- end
-
- describe 'creates a merge request', :smoke do
- it 'user creates a new merge request' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- current_project = Factory::Resource::Project.fabricate! do |project|
- project.name = 'project-with-merge-request'
- end
-
- Factory::Resource::MergeRequest.fabricate! do |merge_request|
- merge_request.title = 'This is a merge request'
- merge_request.description = 'Great feature'
- merge_request.project = current_project
- end
-
- expect(page).to have_content('This is a merge request')
- expect(page).to have_content('Great feature')
- expect(page).to have_content(/Opened [\w\s]+ ago/)
- end
- end
-end
diff --git a/qa/qa/specs/features/merge_request/rebase_spec.rb b/qa/qa/specs/features/merge_request/rebase_spec.rb
deleted file mode 100644
index c36d28e4237..00000000000
--- a/qa/qa/specs/features/merge_request/rebase_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-module QA
- describe 'merge request rebase' do
- it 'rebases source branch of merge request' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- project = Factory::Resource::Project.fabricate! do |project|
- project.name = "only-fast-forward"
- end
-
- Page::Menu::Side.act { go_to_settings }
- Page::Project::Settings::MergeRequest.act { enable_ff_only }
-
- merge_request = Factory::Resource::MergeRequest.fabricate! do |merge_request|
- merge_request.project = project
- merge_request.title = 'Needs rebasing'
- end
-
- Factory::Repository::ProjectPush.fabricate! do |push|
- push.project = project
- push.file_name = "other.txt"
- push.file_content = "New file added!"
- end
-
- merge_request.visit!
-
- Page::MergeRequest::Show.perform do |merge_request|
- expect(merge_request).to have_content('Needs rebasing')
- expect(merge_request).not_to be_fast_forward_possible
- expect(merge_request).not_to have_merge_button
-
- merge_request.rebase!
-
- expect(merge_request).to have_merge_button
- expect(merge_request.fast_forward_possible?).to be_truthy
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/merge_request/squash_spec.rb b/qa/qa/specs/features/merge_request/squash_spec.rb
deleted file mode 100644
index 3ecc36a5ae1..00000000000
--- a/qa/qa/specs/features/merge_request/squash_spec.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-module QA
- describe 'merge request squash commits' do
- it 'when squash commits is marked before merge' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- project = Factory::Resource::Project.fabricate! do |project|
- project.name = "squash-before-merge"
- end
-
- merge_request = Factory::Resource::MergeRequest.fabricate! do |merge_request|
- merge_request.project = project
- merge_request.title = 'Squashing commits'
- end
-
- Factory::Repository::ProjectPush.fabricate! do |push|
- push.project = project
- push.commit_message = 'to be squashed'
- push.branch_name = merge_request.source_branch
- push.new_branch = false
- push.file_name = 'other.txt'
- push.file_content = "Test with unicode characters ❤✓€❄"
- end
-
- merge_request.visit!
-
- expect(page).to have_text('to be squashed')
-
- Page::MergeRequest::Show.perform do |merge_request_page|
- merge_request_page.mark_to_squash
- merge_request_page.merge!
-
- merge_request.project.visit!
-
- Git::Repository.perform do |repository|
- repository.uri = Page::Project::Show.act do
- choose_repository_clone_http
- repository_location.uri
- end
-
- repository.use_default_credentials
-
- repository.act { clone }
-
- expect(repository.commits.size).to eq 3
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/project/activity_spec.rb b/qa/qa/specs/features/project/activity_spec.rb
deleted file mode 100644
index c7ce8dfdcc6..00000000000
--- a/qa/qa/specs/features/project/activity_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module QA
- describe 'activity page' do
- it 'push creates an event in the activity page' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- Factory::Repository::ProjectPush.fabricate! do |push|
- push.file_name = 'README.md'
- push.file_content = '# This is a test project'
- push.commit_message = 'Add README.md'
- end
-
- Page::Menu::Side.act { go_to_activity }
-
- Page::Project::Activity.act { go_to_push_events }
-
- expect(page).to have_content('pushed new branch master')
- end
- end
-end
diff --git a/qa/qa/specs/features/project/add_deploy_key_spec.rb b/qa/qa/specs/features/project/add_deploy_key_spec.rb
deleted file mode 100644
index 24f9f4c77f8..00000000000
--- a/qa/qa/specs/features/project/add_deploy_key_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module QA
- describe 'deploy keys support' do
- it 'user adds a deploy key' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- key = Runtime::Key::RSA.new
- deploy_key_title = 'deploy key title'
- deploy_key_value = key.public_key
-
- deploy_key = Factory::Resource::DeployKey.fabricate! do |resource|
- resource.title = deploy_key_title
- resource.key = deploy_key_value
- end
-
- expect(deploy_key.fingerprint).to eq(key.fingerprint)
- end
- end
-end
diff --git a/qa/qa/specs/features/project/add_secret_variable_spec.rb b/qa/qa/specs/features/project/add_secret_variable_spec.rb
deleted file mode 100644
index 04d9fe488e2..00000000000
--- a/qa/qa/specs/features/project/add_secret_variable_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-module QA
- describe 'secret variables support' do
- it 'user adds a secret variable' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- Factory::Resource::SecretVariable.fabricate! do |resource|
- resource.key = 'VARIABLE_KEY'
- resource.value = 'some secret variable'
- end
-
- Page::Project::Settings::CICD.perform do |settings|
- settings.expand_secret_variables do |page|
- expect(page).to have_field(with: 'VARIABLE_KEY')
- expect(page).not_to have_field(with: 'some secret variable')
-
- page.reveal_variables
-
- expect(page).to have_field(with: 'some secret variable')
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/project/auto_devops_spec.rb b/qa/qa/specs/features/project/auto_devops_spec.rb
deleted file mode 100644
index 248669b6046..00000000000
--- a/qa/qa/specs/features/project/auto_devops_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require 'pathname'
-
-module QA
- describe 'Auto Devops', :orchestrated, :kubernetes do
- after do
- @cluster&.remove!
- end
-
- it 'user creates a new project and runs auto devops' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- project = Factory::Resource::Project.fabricate! do |p|
- p.name = 'project-with-autodevops'
- p.description = 'Project with Auto Devops'
- end
-
- # Disable code_quality check in Auto DevOps pipeline as it takes
- # too long and times out the test
- Factory::Resource::SecretVariable.fabricate! do |resource|
- resource.key = 'CODE_QUALITY_DISABLED'
- resource.value = '1'
- end
-
- # Create Auto Devops compatible repo
- Factory::Repository::ProjectPush.fabricate! do |push|
- push.project = project
- push.directory = Pathname
- .new(__dir__)
- .join('../../../fixtures/auto_devops_rack')
- push.commit_message = 'Create Auto DevOps compatible rack application'
- end
-
- Page::Project::Show.act { wait_for_push }
-
- # Create and connect K8s cluster
- @cluster = Service::KubernetesCluster.new.create!
- kubernetes_cluster = Factory::Resource::KubernetesCluster.fabricate! do |cluster|
- cluster.project = project
- cluster.cluster = @cluster
- cluster.install_helm_tiller = true
- cluster.install_ingress = true
- cluster.install_prometheus = true
- cluster.install_runner = true
- end
-
- project.visit!
- Page::Menu::Side.act { click_ci_cd_settings }
- Page::Project::Settings::CICD.perform do |p|
- p.enable_auto_devops_with_domain("#{kubernetes_cluster.ingress_ip}.nip.io")
- end
-
- project.visit!
- Page::Menu::Side.act { click_ci_cd_pipelines }
- Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
-
- Page::Project::Pipeline::Show.perform do |pipeline|
- expect(pipeline).to have_build('build', status: :success, wait: 600)
- expect(pipeline).to have_build('test', status: :success, wait: 600)
- expect(pipeline).to have_build('production', status: :success, wait: 1200)
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/project/create_issue_spec.rb b/qa/qa/specs/features/project/create_issue_spec.rb
deleted file mode 100644
index 793e7db87cb..00000000000
--- a/qa/qa/specs/features/project/create_issue_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module QA
- describe 'creates issue', :smoke do
- let(:issue_title) { 'issue title' }
-
- it 'user creates issue' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- Factory::Resource::Issue.fabricate! do |issue|
- issue.title = issue_title
- end
-
- Page::Menu::Side.act { click_issues }
-
- expect(page).to have_content(issue_title)
- end
- end
-end
diff --git a/qa/qa/specs/features/project/create_spec.rb b/qa/qa/specs/features/project/create_spec.rb
deleted file mode 100644
index 5e19e490778..00000000000
--- a/qa/qa/specs/features/project/create_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module QA
- describe 'create a new project', :smoke do
- it 'user creates a new project' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- created_project = Factory::Resource::Project.fabricate! do |project|
- project.name = 'awesome-project'
- project.description = 'create awesome project test'
- end
-
- expect(created_project.name).to match /^awesome-project-\h{16}$/
-
- expect(page).to have_content(
- /Project \S?awesome-project\S+ was successfully created/
- )
-
- expect(page).to have_content('create awesome project test')
- expect(page).to have_content('The repository for this project is empty')
- end
- end
-end
diff --git a/qa/qa/specs/features/project/deploy_key_clone_spec.rb b/qa/qa/specs/features/project/deploy_key_clone_spec.rb
deleted file mode 100644
index 1d099508c24..00000000000
--- a/qa/qa/specs/features/project/deploy_key_clone_spec.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-require 'digest/sha1'
-
-module QA
- describe 'cloning code using a deploy key', :docker do
- def login
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
- end
-
- before(:all) do
- login
-
- @runner_name = "qa-runner-#{Time.now.to_i}"
-
- @project = Factory::Resource::Project.fabricate! do |resource|
- resource.name = 'deploy-key-clone-project'
- end
-
- @repository_location = @project.repository_ssh_location
-
- Factory::Resource::Runner.fabricate! do |resource|
- resource.project = @project
- resource.name = @runner_name
- resource.tags = %w[qa docker]
- resource.image = 'gitlab/gitlab-runner:ubuntu'
- end
-
- Page::Menu::Main.act { sign_out }
- end
-
- after(:all) do
- Service::Runner.new(@runner_name).remove!
- end
-
- keys = [
- [Runtime::Key::RSA, 8192],
- [Runtime::Key::ECDSA, 521],
- [Runtime::Key::ED25519]
- ]
-
- keys.each do |(key_class, bits)|
- it "user sets up a deploy key with #{key_class}(#{bits}) to clone code using pipelines" do
- key = key_class.new(*bits)
-
- login
-
- Factory::Resource::DeployKey.fabricate! do |resource|
- resource.project = @project
- resource.title = "deploy key #{key.name}(#{key.bits})"
- resource.key = key.public_key
- end
-
- deploy_key_name = "DEPLOY_KEY_#{key.name}_#{key.bits}"
-
- Factory::Resource::SecretVariable.fabricate! do |resource|
- resource.project = @project
- resource.key = deploy_key_name
- resource.value = key.private_key
- end
-
- gitlab_ci = <<~YAML
- cat-config:
- script:
- - mkdir -p ~/.ssh
- - ssh-keyscan -p #{@repository_location.port} #{@repository_location.host} >> ~/.ssh/known_hosts
- - eval $(ssh-agent -s)
- - ssh-add -D
- - echo "$#{deploy_key_name}" | ssh-add -
- - git clone #{@repository_location.git_uri}
- - cd #{@project.name}
- - git checkout #{deploy_key_name}
- - sha1sum .gitlab-ci.yml
- tags:
- - qa
- - docker
- YAML
-
- Factory::Repository::ProjectPush.fabricate! do |resource|
- resource.project = @project
- resource.file_name = '.gitlab-ci.yml'
- resource.commit_message = 'Add .gitlab-ci.yml'
- resource.file_content = gitlab_ci
- resource.branch_name = deploy_key_name
- resource.new_branch = true
- end
-
- sha1sum = Digest::SHA1.hexdigest(gitlab_ci)
-
- Page::Project::Show.act { wait_for_push }
- Page::Menu::Side.act { click_ci_cd_pipelines }
- Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
- Page::Project::Pipeline::Show.act { go_to_first_job }
-
- Page::Project::Job::Show.perform do |job|
- job.wait(reload: false) do
- job.completed? && !job.trace_loading?
- end
-
- expect(job.passed?).to be_truthy, "Job status did not become \"passed\"."
- expect(job.output).to include(sha1sum)
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/project/file_spec.rb b/qa/qa/specs/features/project/file_spec.rb
deleted file mode 100644
index 5659784cd5c..00000000000
--- a/qa/qa/specs/features/project/file_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-module QA
- describe 'File Functionality', :core do
- it 'lets a user create, edit and delete a file via WebUI' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- # Create
- file_name = 'QA Test - File name'
- file_content = 'QA Test - File content'
- commit_message_for_create = 'QA Test - Create new file'
-
- Factory::Resource::File.fabricate! do |file|
- file.name = file_name
- file.content = file_content
- file.commit_message = commit_message_for_create
- end
-
- expect(page).to have_content('The file has been successfully created.')
- expect(page).to have_content(file_name)
- expect(page).to have_content(file_content)
- expect(page).to have_content(commit_message_for_create)
-
- # Edit
- updated_file_content = 'QA Test - Updated file content'
- commit_message_for_update = 'QA Test - Update file'
-
- Page::File::Show.act { click_edit }
-
- Page::File::Form.act do
- remove_content
- add_content(updated_file_content)
- add_commit_message(commit_message_for_update)
- commit_changes
- end
-
- expect(page).to have_content('Your changes have been successfully committed.')
- expect(page).to have_content(updated_file_content)
- expect(page).to have_content(commit_message_for_update)
-
- # Delete
- commit_message_for_delete = 'QA Test - Delete file'
-
- Page::File::Show.act do
- click_delete
- add_commit_message(commit_message_for_delete)
- click_delete_file
- end
-
- expect(page).to have_content('The file has been successfully deleted.')
- expect(page).to have_content(commit_message_for_delete)
- expect(page).to have_no_content(file_name)
- end
- end
-end
diff --git a/qa/qa/specs/features/project/fork_project_spec.rb b/qa/qa/specs/features/project/fork_project_spec.rb
deleted file mode 100644
index 280978bb950..00000000000
--- a/qa/qa/specs/features/project/fork_project_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module QA
- describe 'Project fork' do
- it 'can submit merge requests to upstream master' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- merge_request = Factory::Resource::MergeRequestFromFork.fabricate! do |merge_request|
- merge_request.fork_branch = 'feature-branch'
- end
-
- Page::Menu::Main.perform { |main| main.sign_out }
- Page::Main::Login.perform { |login| login.sign_in_using_credentials }
-
- merge_request.visit!
-
- Page::MergeRequest::Show.perform { |show| show.merge! }
-
- expect(page).to have_content('The changes were merged')
- end
- end
-end
diff --git a/qa/qa/specs/features/project/import_from_github_spec.rb b/qa/qa/specs/features/project/import_from_github_spec.rb
deleted file mode 100644
index 57695d2c726..00000000000
--- a/qa/qa/specs/features/project/import_from_github_spec.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-module QA
- describe 'user imports a GitHub repo', :orchestrated, :github do
- let(:imported_project) do
- Factory::Resource::ProjectImportedFromGithub.fabricate! do |project|
- project.name = 'imported-project'
- project.personal_access_token = Runtime::Env.github_access_token
- project.github_repository_path = 'gitlab-qa/test-project'
- end
- end
-
- after do
- # We need to delete the imported project because it's impossible to import
- # the same GitHub project twice for a given user.
- api_client = Runtime::API::Client.new(:gitlab)
- delete_project_request = Runtime::API::Request.new(api_client, "/projects/#{CGI.escape("#{Runtime::Namespace.path}/#{imported_project.name}")}")
- delete delete_project_request.url
-
- expect_status(202)
- end
-
- it 'user imports a GitHub repo' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- imported_project # import the project
-
- Page::Menu::Main.act { go_to_projects }
- Page::Dashboard::Projects.perform do |dashboard|
- dashboard.go_to_project(imported_project.name)
- end
-
- Page::Project::Show.act { wait_for_import }
-
- verify_repository_import
- verify_issues_import
- verify_merge_requests_import
- verify_labels_import
- verify_milestones_import
- verify_wiki_import
- end
-
- def verify_repository_import
- expect(page).to have_content('This test project is used for automated GitHub import by GitLab QA.')
- expect(page).to have_content(imported_project.name)
- end
-
- def verify_issues_import
- Page::Menu::Side.act { click_issues }
- expect(page).to have_content('This is a sample issue')
-
- click_link 'This is a sample issue'
-
- expect(page).to have_content('We should populate this project with issues, pull requests and wiki pages.')
-
- # Comments
- expect(page).to have_content('This is a comment from @rymai.')
-
- Page::Issuable::Sidebar.perform do |issuable|
- expect(issuable).to have_label('enhancement')
- expect(issuable).to have_label('help wanted')
- expect(issuable).to have_label('good first issue')
- end
- end
-
- def verify_merge_requests_import
- Page::Menu::Side.act { click_merge_requests }
- expect(page).to have_content('Improve README.md')
-
- click_link 'Improve README.md'
-
- expect(page).to have_content('This improves the README file a bit.')
-
- # Review comment are not supported yet
- expect(page).not_to have_content('Really nice change.')
-
- # Comments
- expect(page).to have_content('Nice work! This is a comment from @rymai.')
-
- # Diff comments
- expect(page).to have_content('[Review comment] I like that!')
- expect(page).to have_content('[Review comment] Nice blank line.')
- expect(page).to have_content('[Single diff comment] Much better without this line!')
-
- Page::Issuable::Sidebar.perform do |issuable|
- expect(issuable).to have_label('bug')
- expect(issuable).to have_label('enhancement')
- end
- end
-
- def verify_labels_import
- # TODO: Waiting on https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/19228
- # to build upon it.
- end
-
- def verify_milestones_import
- # TODO: Waiting on https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18727
- # to build upon it.
- end
-
- def verify_wiki_import
- Page::Menu::Side.act { click_wiki }
-
- expect(page).to have_content('Welcome to the test-project wiki!')
- end
- end
-end
diff --git a/qa/qa/specs/features/project/pipelines_spec.rb b/qa/qa/specs/features/project/pipelines_spec.rb
deleted file mode 100644
index 6c6b4e80626..00000000000
--- a/qa/qa/specs/features/project/pipelines_spec.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-module QA
- describe 'CI/CD Pipelines', :orchestrated, :docker do
- let(:executor) { "qa-runner-#{Time.now.to_i}" }
-
- after do
- Service::Runner.new(executor).remove!
- end
-
- it 'user registers a new specific runner' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- Factory::Resource::Runner.fabricate! do |runner|
- runner.name = executor
- end
-
- Page::Project::Settings::CICD.perform do |settings|
- sleep 5 # Runner should register within 5 seconds
- settings.refresh
-
- settings.expand_runners_settings do |page|
- expect(page).to have_content(executor)
- expect(page).to have_online_runner
- end
- end
- end
-
- it 'users creates a new pipeline' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- project = Factory::Resource::Project.fabricate! do |project|
- project.name = 'project-with-pipelines'
- project.description = 'Project with CI/CD Pipelines.'
- end
-
- Factory::Resource::Runner.fabricate! do |runner|
- runner.project = project
- runner.name = executor
- runner.tags = %w[qa test]
- end
-
- Factory::Repository::ProjectPush.fabricate! do |push|
- push.project = project
- push.file_name = '.gitlab-ci.yml'
- push.commit_message = 'Add .gitlab-ci.yml'
- push.file_content = <<~EOF
- test-success:
- tags:
- - qa
- - test
- script: echo 'OK'
-
- test-failure:
- tags:
- - qa
- - test
- script:
- - echo 'FAILURE'
- - exit 1
-
- test-tags:
- tags:
- - qa
- - docker
- script: echo 'NOOP'
-
- test-artifacts:
- tags:
- - qa
- - test
- script: mkdir my-artifacts; echo "CONTENTS" > my-artifacts/artifact.txt
- artifacts:
- paths:
- - my-artifacts/
- EOF
- end
-
- Page::Project::Show.act { wait_for_push }
-
- expect(page).to have_content('Add .gitlab-ci.yml')
-
- Page::Menu::Side.act { click_ci_cd_pipelines }
-
- expect(page).to have_content('All 1')
- expect(page).to have_content('Add .gitlab-ci.yml')
-
- puts 'Waiting for the runner to process the pipeline'
- sleep 15 # Runner should process all jobs within 15 seconds.
-
- Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
-
- Page::Project::Pipeline::Show.perform do |pipeline|
- expect(pipeline).to be_running
- expect(pipeline).to have_build('test-success', status: :success)
- expect(pipeline).to have_build('test-failure', status: :failed)
- expect(pipeline).to have_build('test-tags', status: :pending)
- expect(pipeline).to have_build('test-artifacts', status: :success)
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/project/wikis_spec.rb b/qa/qa/specs/features/project/wikis_spec.rb
deleted file mode 100644
index 9af2dbd1264..00000000000
--- a/qa/qa/specs/features/project/wikis_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-module QA
- describe 'Wiki Functionality' do
- def login
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
- end
-
- def validate_content(content)
- expect(page).to have_content('Wiki was successfully updated')
- expect(page).to have_content(/#{content}/)
- end
-
- before do
- login
- end
-
- it 'User creates, edits, clones, and pushes to the wiki' do
- wiki = Factory::Resource::Wiki.fabricate! do |resource|
- resource.title = 'Home'
- resource.content = '# My First Wiki Content'
- resource.message = 'Update home'
- end
-
- validate_content('My First Wiki Content')
-
- Page::Project::Wiki::Edit.act { go_to_edit_page }
- Page::Project::Wiki::New.perform do |page|
- page.set_content("My Second Wiki Content")
- page.save_changes
- end
-
- validate_content('My Second Wiki Content')
-
- Factory::Repository::WikiPush.fabricate! do |push|
- push.wiki = wiki
- push.file_name = 'Home.md'
- push.file_content = '# My Third Wiki Content'
- push.commit_message = 'Update Home.md'
- end
- Page::Menu::Side.act { click_wiki }
-
- expect(page).to have_content('My Third Wiki Content')
- end
- end
-end
diff --git a/qa/qa/specs/features/repository/protected_branches_spec.rb b/qa/qa/specs/features/repository/protected_branches_spec.rb
deleted file mode 100644
index 5ae01a12425..00000000000
--- a/qa/qa/specs/features/repository/protected_branches_spec.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-module QA
- describe 'branch protection support', :ldap do
- let(:branch_name) { 'protected-branch' }
- let(:commit_message) { 'Protected push commit message' }
- let(:project) do
- Factory::Resource::Project.fabricate! do |resource|
- resource.name = 'protected-branch-project'
- end
- end
-
- before do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
- end
-
- after do
- # We need to clear localStorage because we're using it for the dropdown,
- # and capybara doesn't do this for us.
- # https://github.com/teamcapybara/capybara/issues/1702
- Capybara.execute_script 'localStorage.clear()'
- end
-
- context 'when developers and maintainers are allowed to push to a protected branch' do
- it 'user with push rights successfully pushes to the protected branch' do
- create_protected_branch(allow_to_push: true)
-
- push = push_new_file(branch_name)
-
- expect(push.output).to match(/remote: To create a merge request for protected-branch, visit/)
- end
- end
-
- context 'when developers and maintainers are not allowed to push to a protected branch' do
- it 'user without push rights fails to push to the protected branch' do
- create_protected_branch(allow_to_push: false)
-
- push = push_new_file(branch_name)
-
- expect(push.output)
- .to match(/remote\: GitLab\: You are not allowed to push code to protected branches on this project/)
- expect(push.output)
- .to match(/\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/)
- end
- end
-
- def create_protected_branch(allow_to_push:)
- Factory::Resource::Branch.fabricate! do |resource|
- resource.branch_name = branch_name
- resource.project = project
- resource.allow_to_push = allow_to_push
- resource.protected = true
- end
- end
-
- def push_new_file(branch)
- Factory::Repository::ProjectPush.fabricate! do |resource|
- resource.project = project
- resource.file_name = 'new_file.md'
- resource.file_content = '# This is a new file'
- resource.commit_message = 'Add new_file.md'
- resource.branch_name = branch_name
- resource.new_branch = false
- end
- end
- end
-end
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index ccc0b906845..5493a33cd2a 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -104,6 +104,8 @@ describe QA::Runtime::Env do
describe '.github_access_token' do
it 'returns "" if GITHUB_ACCESS_TOKEN is not defined' do
+ stub_env('GITHUB_ACCESS_TOKEN', nil)
+
expect(described_class.github_access_token).to eq('')
end
@@ -115,6 +117,8 @@ describe QA::Runtime::Env do
describe '.require_github_access_token!' do
it 'raises ArgumentError if GITHUB_ACCESS_TOKEN is not defined' do
+ stub_env('GITHUB_ACCESS_TOKEN', nil)
+
expect { described_class.require_github_access_token! }.to raise_error(ArgumentError)
end
diff --git a/qa/spec/scenario/test/instance/all_spec.rb b/qa/spec/scenario/test/instance/all_spec.rb
index 423527e938e..1d96352550b 100644
--- a/qa/spec/scenario/test/instance/all_spec.rb
+++ b/qa/spec/scenario/test/instance/all_spec.rb
@@ -1,4 +1,10 @@
describe QA::Scenario::Test::Instance::All do
+ subject do
+ Class.new(described_class) do
+ tags :rspec, :foo
+ end
+ end
+
context '#perform' do
let(:arguments) { spy('Runtime::Scenario') }
let(:release) { spy('Runtime::Release') }
@@ -24,7 +30,7 @@ describe QA::Scenario::Test::Instance::All do
subject.perform("test")
expect(runner).to have_received(:options=)
- .with(::File.expand_path('../../../../qa/specs/features', __dir__))
+ .with(['--tag', 'rspec,foo', '--', ::File.expand_path('../../../../qa/specs/features', __dir__)])
end
end
diff --git a/qa/spec/scenario/test/instance/smoke_spec.rb b/qa/spec/scenario/test/instance/smoke_spec.rb
index e79d19e8212..386eefae930 100644
--- a/qa/spec/scenario/test/instance/smoke_spec.rb
+++ b/qa/spec/scenario/test/instance/smoke_spec.rb
@@ -30,7 +30,7 @@ describe QA::Scenario::Test::Instance::Smoke do
subject.perform("test")
expect(runner).to have_received(:options=)
- .with(::File.expand_path('../../../../qa/specs/features', __dir__))
+ .with(['--tag', 'smoke', '--', ::File.expand_path('../../../../qa/specs/features', __dir__)])
end
end
diff --git a/rubocop/cop/line_break_around_conditional_block.rb b/rubocop/cop/line_break_around_conditional_block.rb
index 011f2bcf8bf..59fe6e5d98c 100644
--- a/rubocop/cop/line_break_around_conditional_block.rb
+++ b/rubocop/cop/line_break_around_conditional_block.rb
@@ -48,6 +48,8 @@ module RuboCop
MSG = 'Add a line break around conditional blocks'
def on_if(node)
+ # This cop causes errors in haml files, so let's skip those
+ return if in_haml?(node)
return if node.single_line?
return unless node.if? || node.unless?
@@ -116,6 +118,10 @@ module RuboCop
def end_line?(line)
line =~ /^\s*(end|})/
end
+
+ def in_haml?(node)
+ node.location.expression.source_buffer.name.end_with?('.haml.rb')
+ end
end
end
end
diff --git a/rubocop/cop/ruby_interpolation_in_translation.rb b/rubocop/cop/ruby_interpolation_in_translation.rb
new file mode 100644
index 00000000000..b9411fcfd6c
--- /dev/null
+++ b/rubocop/cop/ruby_interpolation_in_translation.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ class RubyInterpolationInTranslation < RuboCop::Cop::Cop
+ MSG = "Don't use ruby interpolation \#{} inside translated strings, instead use \%{}"
+
+ TRANSLATION_METHODS = ':_ :s_ :N_ :n_'
+ RUBY_INTERPOLATION_REGEX = /.*\#\{.*\}/
+
+ def_node_matcher :translation_method?, <<~PATTERN
+ (send nil? {#{TRANSLATION_METHODS}} $dstr ...)
+ PATTERN
+
+ def_node_matcher :plural_translation_method?, <<~PATTERN
+ (send nil? :n_ str $dstr ...)
+ PATTERN
+
+ def on_send(node)
+ interpolation = translation_method?(node) || plural_translation_method?(node)
+ return unless interpolation
+
+ interpolation.descendants.each do |possible_violation|
+ add_offense(possible_violation, message: MSG) if possible_violation.type != :str
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 88c9bbf24f4..eaf421a7235 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -28,3 +28,4 @@ require_relative 'cop/rspec/env_assignment'
require_relative 'cop/rspec/factories_in_migration_specs'
require_relative 'cop/sidekiq_options_queue'
require_relative 'cop/destroy_all'
+require_relative 'cop/ruby_interpolation_in_translation'
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
index f7068546093..465f3499703 100644
--- a/spec/controllers/groups/milestones_controller_spec.rb
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -141,6 +141,17 @@ describe Groups::MilestonesController do
end
end
+ describe "#destroy" do
+ let(:milestone) { create(:milestone, group: group) }
+
+ it "removes milestone" do
+ delete :destroy, group_id: group.to_param, id: milestone.iid, format: :js
+
+ expect(response).to be_success
+ expect { Milestone.find(milestone.id) }.to raise_exception(ActiveRecord::RecordNotFound)
+ end
+ end
+
describe '#ensure_canonical_path' do
before do
sign_in(user)
diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
index d8995f98575..f8c37c0a676 100644
--- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
@@ -29,6 +29,55 @@ describe Projects::MergeRequests::CreationsController do
expect(response).to be_success
end
end
+
+ context 'merge request with some commits' do
+ render_views
+
+ let(:large_diff_params) do
+ {
+ namespace_id: fork_project.namespace.to_param,
+ project_id: fork_project,
+ merge_request: {
+ source_branch: 'master',
+ target_branch: 'fix'
+ }
+ }
+ end
+
+ describe 'with artificial limits' do
+ before do
+ # Load MergeRequestdiff so stub_const won't override it with its own definition
+ # See https://github.com/rspec/rspec-mocks/issues/1079
+ stub_const("#{MergeRequestDiff}::COMMITS_SAFE_SIZE", 2)
+ end
+
+ it 'limits total commits' do
+ get :new, large_diff_params
+
+ expect(response).to be_success
+
+ total = assigns(:total_commit_count)
+ expect(assigns(:commits)).to be_an Array
+ expect(total).to be > 0
+ expect(assigns(:hidden_commit_count)).to be > 0
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.body).to match %r(<span class="commits-count">2 commits</span>)
+ end
+ end
+
+ it 'shows total commits' do
+ get :new, large_diff_params
+
+ expect(response).to be_success
+
+ total = assigns(:total_commit_count)
+ expect(assigns(:commits)).to be_an Array
+ expect(total).to be > 0
+ expect(assigns(:hidden_commit_count)).to eq(0)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.body).to match %r(<span class="commits-count">#{total} commits</span>)
+ end
+ end
end
describe 'GET diffs' do
diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb
index 019e4420212..027349b2f8e 100644
--- a/spec/factories/milestones.rb
+++ b/spec/factories/milestones.rb
@@ -34,7 +34,7 @@ FactoryBot.define do
milestone.project_id = evaluator.project_id
elsif evaluator.parent
id = evaluator.parent.id
- evaluator.parent.is_a?(Group) ? board.group_id = id : evaluator.project_id = id
+ evaluator.parent.is_a?(Group) ? evaluator.group_id = id : evaluator.project_id = id
else
milestone.project = create(:project)
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 1db6c75b85b..b2eaeb1c487 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -134,6 +134,7 @@ describe "Admin::Users" do
expect(page).to have_content(user.email)
expect(page).to have_content(user.name)
+ expect(page).to have_content(user.id)
expect(page).to have_link('Block user', href: block_admin_user_path(user))
expect(page).to have_button('Delete user')
expect(page).to have_button('Delete user and contributions')
diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb
index 0db69432702..d9d67788b38 100644
--- a/spec/features/dashboard/milestones_spec.rb
+++ b/spec/features/dashboard/milestones_spec.rb
@@ -13,8 +13,10 @@ describe 'Dashboard > Milestones' do
describe 'as logged-in user' do
let(:user) { create(:user) }
+ let(:group) { create(:group) }
let(:project) { create(:project, namespace: user.namespace) }
let!(:milestone) { create(:milestone, project: project) }
+ let!(:milestone2) { create(:milestone, group: group) }
before do
project.add_maintainer(user)
sign_in(user)
@@ -24,6 +26,7 @@ describe 'Dashboard > Milestones' do
it 'sees milestones' do
expect(current_path).to eq dashboard_milestones_path
expect(page).to have_content(milestone.title)
+ expect(page).to have_content(group.name)
end
end
end
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index d6e7ff33d5d..0c15febe8df 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -2,6 +2,7 @@ require 'rails_helper'
describe 'Merge request > User sees diff', :js do
include ProjectForksHelper
+ include RepoHelpers
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
@@ -81,5 +82,58 @@ describe 'Merge request > User sees diff', :js do
expect(page).to have_selector('.js-cancel-fork-suggestion-button', count: 1)
end
end
+
+ context 'when file contains html' do
+ let(:current_user) { project.owner }
+ let(:branch_name) {"test_branch"}
+
+ def create_file(branch_name, file_name, content)
+ Files::CreateService.new(
+ project,
+ current_user,
+ start_branch: branch_name,
+ branch_name: branch_name,
+ commit_message: "Create file",
+ file_path: file_name,
+ file_content: content
+ ).execute
+
+ project.commit(branch_name)
+ end
+
+ it 'escapes any HTML special characters in the diff chunk header' do
+ file_content =
+ <<~CONTENT
+ function foo<input> {
+ let a = 1;
+ let b = 2;
+ let c = 3;
+ let d = 3;
+ }
+ CONTENT
+
+ new_file_content =
+ <<~CONTENT
+ function foo<input> {
+ let a = 1;
+ let b = 2;
+ let c = 3;
+ let x = 3;
+ }
+ CONTENT
+
+ file_name = 'xss_file.txt'
+
+ create_file('master', file_name, file_content)
+ merge_request = create(:merge_request, source_project: project)
+ create_file(merge_request.source_branch, file_name, new_file_content)
+
+ project.commit(merge_request.source_branch)
+
+ visit diffs_project_merge_request_path(project, merge_request)
+
+ expect(page).to have_text("function foo<input> {")
+ end
+ end
end
end
diff --git a/spec/features/milestones/user_deletes_milestone_spec.rb b/spec/features/milestones/user_deletes_milestone_spec.rb
index 9d4a68239d3..a8c296b4cd2 100644
--- a/spec/features/milestones/user_deletes_milestone_spec.rb
+++ b/spec/features/milestones/user_deletes_milestone_spec.rb
@@ -1,26 +1,46 @@
require "rails_helper"
describe "User deletes milestone", :js do
- set(:user) { create(:user) }
- set(:project) { create(:project) }
- set(:milestone) { create(:milestone, project: project) }
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
before do
- project.add_developer(user)
sign_in(user)
+ end
+
+ context "when milestone belongs to project" do
+ let!(:milestone) { create(:milestone, parent: project, title: "project milestone") }
+
+ it "deletes milestone" do
+ project.add_developer(user)
+ visit(project_milestones_path(project))
+ click_link(milestone.title)
+ click_button("Delete")
+ click_button("Delete milestone")
+
+ expect(page).to have_content("No milestones to show")
+
+ visit(activity_project_path(project))
- visit(project_milestones_path(project))
+ expect(page).to have_content("#{user.name} destroyed milestone")
+ end
end
- it "deletes milestone" do
- click_link(milestone.title)
- click_button("Delete")
- click_button("Delete milestone")
+ context "when milestone belongs to group" do
+ let!(:milestone_to_be_deleted) { create(:milestone, parent: group, title: "group milestone 1") }
+ let!(:milestone) { create(:milestone, parent: group, title: "group milestone 2") }
- expect(page).to have_content("No milestones to show")
+ it "deletes milestone" do
+ group.add_developer(user)
+ visit(group_milestones_path(group))
- visit(activity_project_path(project))
+ click_link(milestone_to_be_deleted.title)
+ click_button("Delete")
+ click_button("Delete milestone")
- expect(page).to have_content("#{user.name} destroyed milestone")
+ expect(page).to have_content(milestone.title)
+ expect(page).not_to have_content(milestone_to_be_deleted)
+ end
end
end
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 9e60b4995bd..206a3a4fe9a 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -130,5 +130,15 @@ describe 'User edit profile' do
visit user_path(user)
expect(page).not_to have_selector '.cover-status'
end
+
+ it 'displays a default emoji if only message is entered' do
+ message = 'a status without emoji'
+ visit(profile_path)
+ fill_in 'js-status-message-field', with: message
+
+ within('.js-toggle-emoji-menu') do
+ expect(page).to have_emoji('speech_balloon')
+ end
+ end
end
end
diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb
index 50e957bf12b..2d791947ee9 100644
--- a/spec/features/projects/jobs/user_browses_job_spec.rb
+++ b/spec/features/projects/jobs/user_browses_job_spec.rb
@@ -40,7 +40,7 @@ describe 'User browses a job', :js do
it 'displays the failure reason' do
within('.builds-container') do
build_link = first('.build-job > a')
- expect(build_link['data-title']).to eq('test - failed <br> (unknown failure)')
+ expect(build_link['data-title']).to eq('test - failed - (unknown failure)')
end
end
end
@@ -51,7 +51,7 @@ describe 'User browses a job', :js do
it 'displays the failure reason and retried label' do
within('.builds-container') do
build_link = first('.build-job > a')
- expect(build_link['data-title']).to eq('test - failed <br> (unknown failure) (retried)')
+ expect(build_link['data-title']).to eq('test - failed - (unknown failure) (retried)')
end
end
end
diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb
index 08786fe1630..ebc20d15d67 100644
--- a/spec/features/projects/jobs/user_browses_jobs_spec.rb
+++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb
@@ -36,7 +36,7 @@ describe 'User browses jobs' do
it 'displays a tooltip with the failure reason' do
page.within('.ci-table') do
failed_job_link = page.find('.ci-failed')
- expect(failed_job_link[:title]).to eq('Failed <br> (unknown failure)')
+ expect(failed_job_link[:title]).to eq('Failed - (unknown failure)')
end
end
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index a84492ea5f1..603503a531c 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -126,7 +126,7 @@ describe 'Pipeline', :js do
it 'should include the failure reason' do
page.within('#ci-badge-test') do
build_link = page.find('.js-pipeline-graph-job-link')
- expect(build_link['data-original-title']).to eq('test - failed <br> (unknown failure)')
+ expect(build_link['data-original-title']).to eq('test - failed - (unknown failure)')
end
end
end
@@ -319,7 +319,7 @@ describe 'Pipeline', :js do
it 'displays a tooltip with the failure reason' do
page.within('.ci-table') do
failed_job_link = page.find('.ci-failed')
- expect(failed_job_link[:title]).to eq('Failed <br> (unknown failure)')
+ expect(failed_job_link[:title]).to eq('Failed - (unknown failure)')
end
end
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 4a83bcc3efb..26a92f14787 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -406,7 +406,7 @@ describe 'Pipelines', :js do
within('.js-builds-dropdown-list') do
build_element = page.find('.mini-pipeline-graph-dropdown-item')
- expect(build_element['data-original-title']).to eq('build - failed <br> (unknown failure)')
+ expect(build_element['data-original-title']).to eq('build - failed - (unknown failure)')
end
end
end
diff --git a/spec/helpers/import_helper_spec.rb b/spec/helpers/import_helper_spec.rb
index 033155617c6..cb0ea4e26ba 100644
--- a/spec/helpers/import_helper_spec.rb
+++ b/spec/helpers/import_helper_spec.rb
@@ -1,6 +1,16 @@
require 'rails_helper'
describe ImportHelper do
+ describe '#sanitize_project_name' do
+ it 'removes whitespace' do
+ expect(helper.sanitize_project_name('my test repo')).to eq('my-test-repo')
+ end
+
+ it 'removes disallowed characters' do
+ expect(helper.sanitize_project_name('Test&me$over*h_ere')).to eq('Test-me-over-h_ere')
+ end
+ end
+
describe '#import_project_target' do
let(:user) { create(:user) }
diff --git a/spec/javascripts/badges/dummy_badge.js b/spec/javascripts/badges/dummy_badge.js
index 6aaff21c503..f0cdaddbd33 100644
--- a/spec/javascripts/badges/dummy_badge.js
+++ b/spec/javascripts/badges/dummy_badge.js
@@ -1,8 +1,9 @@
+import _ from 'underscore';
import { PROJECT_BADGE } from '~/badges/constants';
import { DUMMY_IMAGE_URL, TEST_HOST } from 'spec/test_constants';
export const createDummyBadge = () => {
- const id = Math.floor(1000 * Math.random());
+ const id = _.uniqueId();
return {
id,
imageUrl: `${TEST_HOST}/badges/${id}/image/url`,
diff --git a/spec/javascripts/flash_spec.js b/spec/javascripts/flash_spec.js
index 7198dbd4cf2..0a8e5a628c0 100644
--- a/spec/javascripts/flash_spec.js
+++ b/spec/javascripts/flash_spec.js
@@ -57,8 +57,11 @@ describe('Flash', () => {
hideFlash(el);
expect(
- el.style.transition,
- ).toBe('opacity 0.3s');
+ el.style['transition-property'],
+ ).toBe('opacity');
+ expect(
+ el.style['transition-duration'],
+ ).toBe('0.3s');
});
it('sets opacity style', () => {
diff --git a/spec/javascripts/helpers/vue_mount_component_helper.js b/spec/javascripts/helpers/vue_mount_component_helper.js
index 1057f0aca3e..6848c95d95d 100644
--- a/spec/javascripts/helpers/vue_mount_component_helper.js
+++ b/spec/javascripts/helpers/vue_mount_component_helper.js
@@ -1,3 +1,5 @@
+import Vue from 'vue';
+
const mountComponent = (Component, props = {}, el = null) =>
new Component({
propsData: props,
@@ -25,4 +27,12 @@ export const mountComponentWithSlots = (Component, { props, slots }) => {
return component.$mount();
};
+/**
+ * Mount a component with the given render method.
+ *
+ * This helps with inserting slots that need to be compiled.
+ */
+export const mountComponentWithRender = (render, el = null) =>
+ mountComponent(Vue.extend({ render }), {}, el);
+
export default mountComponent;
diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
index 24a7d76f30b..06b8b452319 100644
--- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
@@ -184,7 +184,7 @@ describe('IDE commit module actions', () => {
branch,
})
.then(() => {
- expect(f.lastCommit.message).toBe(data.message);
+ expect(f.lastCommitSha).toBe(data.id);
})
.then(done)
.catch(done.fail);
@@ -266,19 +266,21 @@ describe('IDE commit module actions', () => {
});
describe('success', () => {
+ const COMMIT_RESPONSE = {
+ id: '123456',
+ short_id: '123',
+ message: 'test message',
+ committed_date: 'date',
+ stats: {
+ additions: '1',
+ deletions: '2',
+ },
+ };
+
beforeEach(() => {
spyOn(service, 'commit').and.returnValue(
Promise.resolve({
- data: {
- id: '123456',
- short_id: '123',
- message: 'test message',
- committed_date: 'date',
- stats: {
- additions: '1',
- deletions: '2',
- },
- },
+ data: COMMIT_RESPONSE,
}),
);
});
@@ -352,8 +354,8 @@ describe('IDE commit module actions', () => {
store
.dispatch('commit/commitChanges')
.then(() => {
- expect(store.state.entries[store.state.openFiles[0].path].lastCommit.message).toBe(
- 'test message',
+ expect(store.state.entries[store.state.openFiles[0].path].lastCommitSha).toBe(
+ COMMIT_RESPONSE.id,
);
done();
diff --git a/spec/javascripts/jobs/components/environments_block_spec.js b/spec/javascripts/jobs/components/environments_block_spec.js
new file mode 100644
index 00000000000..015c26be9fc
--- /dev/null
+++ b/spec/javascripts/jobs/components/environments_block_spec.js
@@ -0,0 +1,137 @@
+import Vue from 'vue';
+import component from '~/jobs/components/environments_block.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('Environments block', () => {
+ const Component = Vue.extend(component);
+ let vm;
+ const icon = {
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ };
+ const deployment = {
+ path: 'deployment',
+ name: 'deployment name',
+ };
+ const environment = {
+ path: '/environment',
+ name: 'environment',
+ };
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('with latest deployment', () => {
+ it('renders info for most recent deployment', () => {
+ vm = mountComponent(Component, {
+ deploymentStatus: {
+ status: 'latest',
+ icon,
+ deployment,
+ environment,
+ },
+ });
+
+ expect(vm.$el.textContent.trim()).toEqual(
+ 'This job is the most recent deployment to environment.',
+ );
+ });
+ });
+
+ describe('with out of date deployment', () => {
+ describe('with last deployment', () => {
+ it('renders info for out date and most recent', () => {
+ vm = mountComponent(Component, {
+ deploymentStatus: {
+ status: 'out_of_date',
+ icon,
+ deployment,
+ environment: Object.assign({}, environment, {
+ last_deployment: { name: 'deployment', path: 'last_deployment' },
+ }),
+ },
+ });
+
+ expect(vm.$el.textContent.trim()).toEqual(
+ 'This job is an out-of-date deployment to environment. View the most recent deployment deployment.',
+ );
+ });
+ });
+
+ describe('without last deployment', () => {
+ it('renders info about out of date deployment', () => {
+ vm = mountComponent(Component, {
+ deploymentStatus: {
+ status: 'out_of_date',
+ icon,
+ deployment: null,
+ environment,
+ },
+ });
+
+ expect(vm.$el.textContent.trim()).toEqual(
+ 'This job is an out-of-date deployment to environment.',
+ );
+ });
+ });
+ });
+
+ describe('with failed deployment', () => {
+ it('renders info about failed deployment', () => {
+ vm = mountComponent(Component, {
+ deploymentStatus: {
+ status: 'failed',
+ icon,
+ deployment: null,
+ environment,
+ },
+ });
+
+ expect(vm.$el.textContent.trim()).toEqual(
+ 'The deployment of this job to environment did not succeed.',
+ );
+ });
+ });
+
+ describe('creating deployment', () => {
+ describe('with last deployment', () => {
+ it('renders info about creating deployment and overriding lastest deployment', () => {
+ vm = mountComponent(Component, {
+ deploymentStatus: {
+ status: 'creating',
+ icon,
+ deployment,
+ environment: Object.assign({}, environment, {
+ last_deployment: { name: 'deployment', path: 'last_deployment' },
+ }),
+ },
+ });
+
+ expect(vm.$el.textContent.trim()).toEqual(
+ 'This job is creating a deployment to environment and will overwrite the last deployment.',
+ );
+ });
+ });
+
+ describe('without last deployment', () => {
+ it('renders info about failed deployment', () => {
+ vm = mountComponent(Component, {
+ deploymentStatus: {
+ status: 'creating',
+ icon,
+ deployment: null,
+ environment,
+ },
+ });
+
+ expect(vm.$el.textContent.trim()).toEqual(
+ 'This job is creating a deployment to environment.',
+ );
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/performance_bar/services/performance_bar_service_spec.js b/spec/javascripts/performance_bar/services/performance_bar_service_spec.js
new file mode 100644
index 00000000000..bc6947dbe81
--- /dev/null
+++ b/spec/javascripts/performance_bar/services/performance_bar_service_spec.js
@@ -0,0 +1,63 @@
+import PerformanceBarService from '~/performance_bar/services/performance_bar_service';
+
+describe('PerformanceBarService', () => {
+ describe('callbackParams', () => {
+ describe('fireCallback', () => {
+ function fireCallback(response, peekUrl) {
+ return PerformanceBarService.callbackParams(response, peekUrl)[0];
+ }
+
+ it('returns false when the request URL is the peek URL', () => {
+ expect(fireCallback({ headers: { 'x-request-id': '123' }, url: '/peek' }, '/peek'))
+ .toBeFalsy();
+ });
+
+ it('returns false when there is no request ID', () => {
+ expect(fireCallback({ headers: {}, url: '/request' }, '/peek'))
+ .toBeFalsy();
+ });
+
+ it('returns false when the request is an API request', () => {
+ expect(fireCallback({ headers: { 'x-request-id': '123' }, url: '/api/' }, '/peek'))
+ .toBeFalsy();
+ });
+
+ it('returns false when the response is from the cache', () => {
+ expect(fireCallback({ headers: { 'x-request-id': '123', 'x-gitlab-from-cache': 'true' }, url: '/request' }, '/peek'))
+ .toBeFalsy();
+ });
+
+ it('returns true when all conditions are met', () => {
+ expect(fireCallback({ headers: { 'x-request-id': '123' }, url: '/request' }, '/peek'))
+ .toBeTruthy();
+ });
+ });
+
+ describe('requestId', () => {
+ function requestId(response, peekUrl) {
+ return PerformanceBarService.callbackParams(response, peekUrl)[1];
+ }
+
+ it('gets the request ID from the headers', () => {
+ expect(requestId({ headers: { 'x-request-id': '123' } }, '/peek'))
+ .toEqual('123');
+ });
+ });
+
+ describe('requestUrl', () => {
+ function requestUrl(response, peekUrl) {
+ return PerformanceBarService.callbackParams(response, peekUrl)[2];
+ }
+
+ it('gets the request URL from the response object', () => {
+ expect(requestUrl({ headers: {}, url: '/request' }, '/peek'))
+ .toEqual('/request');
+ });
+
+ it('gets the request URL from response.config if present', () => {
+ expect(requestUrl({ headers: {}, config: { url: '/config-url' }, url: '/request' }, '/peek'))
+ .toEqual('/config-url');
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/pipelines/graph/dropdown_job_component_spec.js b/spec/javascripts/pipelines/graph/dropdown_job_component_spec.js
index ff584396d61..2b47ca236b2 100644
--- a/spec/javascripts/pipelines/graph/dropdown_job_component_spec.js
+++ b/spec/javascripts/pipelines/graph/dropdown_job_component_spec.js
@@ -82,12 +82,4 @@ describe('dropdown job component', () => {
it('renders dropdown with jobs', () => {
expect(vm.$el.querySelectorAll('.scrollable-menu>ul>li').length).toEqual(mock.jobs.length);
});
-
- it('escapes tooltip title', () => {
- expect(
- vm.$el.querySelector('.js-pipeline-graph-job-link').getAttribute('data-original-title'),
- ).toEqual(
- '&lt;img src=x onerror=alert(document.domain)&gt; - passed',
- );
- });
});
diff --git a/spec/javascripts/pipelines/graph/job_component_spec.js b/spec/javascripts/pipelines/graph/job_component_spec.js
index 215ce1e81b5..0ae448f2ea8 100644
--- a/spec/javascripts/pipelines/graph/job_component_spec.js
+++ b/spec/javascripts/pipelines/graph/job_component_spec.js
@@ -161,24 +161,4 @@ describe('pipeline graph job component', () => {
expect(component.$el.querySelector(tooltipBoundary)).toBeNull();
});
});
-
- describe('tooltipText', () => {
- it('escapes job name', () => {
- component = mountComponent(JobComponent, {
- job: {
- id: 4259,
- name: '<img src=x onerror=alert(document.domain)>',
- status: {
- icon: 'status_success',
- label: 'success',
- tooltip: 'failed',
- },
- },
- });
-
- expect(
- component.$el.querySelector('.js-job-component-tooltip').getAttribute('data-original-title'),
- ).toEqual('&lt;img src=x onerror=alert(document.domain)&gt; - failed');
- });
- });
});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
index 8ac2f26979b..0e42537faed 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
@@ -45,7 +45,7 @@ describe('MRWidgetHeader', () => {
});
});
- describe('commitsText', () => {
+ describe('commitsBehindText', () => {
it('returns singular when there is one commit', () => {
vm = mountComponent(Component, {
mr: {
@@ -53,11 +53,12 @@ describe('MRWidgetHeader', () => {
sourceBranch: 'mr-widget-refactor',
sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>',
targetBranch: 'master',
+ targetBranchPath: '/foo/bar/master',
statusPath: 'abc',
},
});
- expect(vm.commitsText).toEqual('1 commit behind');
+ expect(vm.commitsBehindText).toEqual('The source branch is <a href="/foo/bar/master">1 commit behind</a> the target branch');
});
it('returns plural when there is more than one commit', () => {
@@ -67,11 +68,12 @@ describe('MRWidgetHeader', () => {
sourceBranch: 'mr-widget-refactor',
sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>',
targetBranch: 'master',
+ targetBranchPath: '/foo/bar/master',
statusPath: 'abc',
},
});
- expect(vm.commitsText).toEqual('2 commits behind');
+ expect(vm.commitsBehindText).toEqual('The source branch is <a href="/foo/bar/master">2 commits behind</a> the target branch');
});
});
});
@@ -280,9 +282,9 @@ describe('MRWidgetHeader', () => {
});
it('renders diverged commits info', () => {
- expect(vm.$el.querySelector('.diverged-commits-count').textContent).toMatch(
- /(mr-widget-refactor[\s\S]+?is 12 commits behind[\s\S]+?master)/,
- );
+ expect(vm.$el.querySelector('.diverged-commits-count').textContent).toEqual('The source branch is 12 commits behind the target branch');
+ expect(vm.$el.querySelector('.diverged-commits-count a').textContent).toEqual('12 commits behind');
+ expect(vm.$el.querySelector('.diverged-commits-count a')).toHaveAttr('href', vm.mr.targetBranchPath);
});
});
});
diff --git a/spec/javascripts/vue_shared/components/stacked_progress_bar_spec.js b/spec/javascripts/vue_shared/components/stacked_progress_bar_spec.js
index 076d940961d..f1fe2e996fc 100644
--- a/spec/javascripts/vue_shared/components/stacked_progress_bar_spec.js
+++ b/spec/javascripts/vue_shared/components/stacked_progress_bar_spec.js
@@ -44,7 +44,11 @@ describe('StackedProgressBarComponent', () => {
});
it('returns percentage with decimal place from provided count based on `totalCount`', () => {
- expect(vm.getPercent(10)).toBe(0.2);
+ expect(vm.getPercent(67)).toBe(1.3);
+ });
+
+ it('returns percentage as `< 1` from provided count based on `totalCount` when evaluated value is less than 1', () => {
+ expect(vm.getPercent(10)).toBe('< 1');
});
});
diff --git a/spec/javascripts/vue_shared/components/tooltip_on_truncate_spec.js b/spec/javascripts/vue_shared/components/tooltip_on_truncate_spec.js
new file mode 100644
index 00000000000..8465757deb6
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/tooltip_on_truncate_spec.js
@@ -0,0 +1,162 @@
+import { mountComponentWithRender } from 'spec/helpers/vue_mount_component_helper';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+
+const TEST_TITLE = 'lorem-ipsum-dolar-sit-amit-consectur-adipiscing-elit-sed-do';
+const CLASS_SHOW_TOOLTIP = 'js-show-tooltip';
+const STYLE_TRUNCATED = {
+ display: 'inline-block',
+ 'max-width': '20px',
+};
+const STYLE_NORMAL = {
+ display: 'inline-block',
+ 'max-width': '1000px',
+};
+
+function mountTooltipOnTruncate(options, createChildren) {
+ return mountComponentWithRender(h => h(TooltipOnTruncate, options, createChildren(h)), '#app');
+}
+
+describe('TooltipOnTruncate component', () => {
+ let vm;
+
+ beforeEach(() => {
+ const el = document.createElement('div');
+ el.id = 'app';
+ document.body.appendChild(el);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('with default target', () => {
+ it('renders tooltip if truncated', done => {
+ const options = {
+ style: STYLE_TRUNCATED,
+ props: {
+ title: TEST_TITLE,
+ },
+ };
+
+ vm = mountTooltipOnTruncate(options, () => [TEST_TITLE]);
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).toHaveClass(CLASS_SHOW_TOOLTIP);
+ expect(vm.$el).toHaveData('original-title', TEST_TITLE);
+ expect(vm.$el).toHaveData('placement', 'top');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('does not render tooltip if normal', done => {
+ const options = {
+ style: STYLE_NORMAL,
+ props: {
+ title: TEST_TITLE,
+ },
+ };
+
+ vm = mountTooltipOnTruncate(options, () => [TEST_TITLE]);
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).not.toHaveClass(CLASS_SHOW_TOOLTIP);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('with child target', () => {
+ it('renders tooltip if truncated', done => {
+ const options = {
+ style: STYLE_NORMAL,
+ props: {
+ title: TEST_TITLE,
+ truncateTarget: 'child',
+ },
+ };
+
+ vm = mountTooltipOnTruncate(options, (h) => [
+ h('a', { style: STYLE_TRUNCATED }, TEST_TITLE),
+ ]);
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).toHaveClass(CLASS_SHOW_TOOLTIP);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('does not render tooltip if normal', done => {
+ const options = {
+ props: {
+ title: TEST_TITLE,
+ truncateTarget: 'child',
+ },
+ };
+
+ vm = mountTooltipOnTruncate(options, (h) => [
+ h('a', { style: STYLE_NORMAL }, TEST_TITLE),
+ ]);
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).not.toHaveClass(CLASS_SHOW_TOOLTIP);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('with fn target', () => {
+ it('renders tooltip if truncated', done => {
+ const options = {
+ style: STYLE_NORMAL,
+ props: {
+ title: TEST_TITLE,
+ truncateTarget: (el) => el.childNodes[1],
+ },
+ };
+
+ vm = mountTooltipOnTruncate(options, (h) => [
+ h('a', { style: STYLE_NORMAL }, TEST_TITLE),
+ h('span', { style: STYLE_TRUNCATED }, TEST_TITLE),
+ ]);
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).toHaveClass(CLASS_SHOW_TOOLTIP);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('placement', () => {
+ it('sets data-placement when tooltip is rendered', done => {
+ const options = {
+ props: {
+ title: TEST_TITLE,
+ truncateTarget: 'child',
+ placement: 'bottom',
+ },
+ };
+
+ vm = mountTooltipOnTruncate(options, (h) => [
+ h('a', { style: STYLE_TRUNCATED }, TEST_TITLE),
+ ]);
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).toHaveClass(CLASS_SHOW_TOOLTIP);
+ expect(vm.$el).toHaveData('placement', options.props.placement);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
index f313e675654..8bb5a843484 100644
--- a/spec/lib/feature_spec.rb
+++ b/spec/lib/feature_spec.rb
@@ -1,6 +1,13 @@
require 'spec_helper'
describe Feature do
+ before do
+ # We mock all calls to .enabled? to return true in order to force all
+ # specs to run the feature flag gated behavior, but here we need a clean
+ # behavior from the class
+ allow(described_class).to receive(:enabled?).and_call_original
+ end
+
describe '.get' do
let(:feature) { double(:feature) }
let(:key) { 'my_feature' }
@@ -106,4 +113,63 @@ describe Feature do
it_behaves_like 'a memoized Flipper instance'
end
end
+
+ describe '.enabled?' do
+ it 'returns false for undefined feature' do
+ expect(described_class.enabled?(:some_random_feature_flag)).to be_falsey
+ end
+
+ it 'returns false for existing disabled feature in the database' do
+ described_class.disable(:disabled_feature_flag)
+
+ expect(described_class.enabled?(:disabled_feature_flag)).to be_falsey
+ end
+
+ it 'returns true for existing enabled feature in the database' do
+ described_class.enable(:enabled_feature_flag)
+
+ expect(described_class.enabled?(:enabled_feature_flag)).to be_truthy
+ end
+
+ context 'with an individual actor' do
+ CustomActor = Struct.new(:flipper_id)
+
+ let(:actor) { CustomActor.new(flipper_id: 'CustomActor:5') }
+ let(:another_actor) { CustomActor.new(flipper_id: 'CustomActor:10') }
+
+ before do
+ described_class.enable(:enabled_feature_flag, actor)
+ end
+
+ it 'returns true when same actor is informed' do
+ expect(described_class.enabled?(:enabled_feature_flag, actor)).to be_truthy
+ end
+
+ it 'returns false when different actor is informed' do
+ expect(described_class.enabled?(:enabled_feature_flag, another_actor)).to be_falsey
+ end
+
+ it 'returns false when no actor is informed' do
+ expect(described_class.enabled?(:enabled_feature_flag)).to be_falsey
+ end
+ end
+ end
+
+ describe '.disable?' do
+ it 'returns true for undefined feature' do
+ expect(described_class.disabled?(:some_random_feature_flag)).to be_truthy
+ end
+
+ it 'returns true for existing disabled feature in the database' do
+ described_class.disable(:disabled_feature_flag)
+
+ expect(described_class.disabled?(:disabled_feature_flag)).to be_truthy
+ end
+
+ it 'returns false for existing enabled feature in the database' do
+ described_class.enable(:enabled_feature_flag)
+
+ expect(described_class.disabled?(:enabled_feature_flag)).to be_falsey
+ end
+ end
end
diff --git a/spec/lib/gitlab/auth/ldap/access_spec.rb b/spec/lib/gitlab/auth/ldap/access_spec.rb
index eff21985108..7800c543cdb 100644
--- a/spec/lib/gitlab/auth/ldap/access_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/access_spec.rb
@@ -3,51 +3,61 @@ require 'spec_helper'
describe Gitlab::Auth::LDAP::Access do
include LdapHelpers
- let(:access) { described_class.new user }
let(:user) { create(:omniauth_user) }
+ subject(:access) { described_class.new(user) }
+
describe '.allowed?' do
- it 'updates the users `last_credential_check_at' do
+ before do
allow(access).to receive(:update_user)
- expect(access).to receive(:allowed?) { true }
- expect(described_class).to receive(:open).and_yield(access)
+ allow(access).to receive(:allowed?).and_return(true)
+ allow(described_class).to receive(:open).and_yield(access)
+ end
+ it "updates the user's `last_credential_check_at`" do
expect { described_class.allowed?(user) }
.to change { user.last_credential_check_at }
end
- end
- describe '#find_ldap_user' do
- it 'finds a user by dn first' do
- expect(Gitlab::Auth::LDAP::Person).to receive(:find_by_dn).and_return(:ldap_user)
+ it "does not update user's `last_credential_check_at` when in a read-only GitLab instance" do
+ allow(Gitlab::Database).to receive(:read_only?).and_return(true)
- access.find_ldap_user
+ expect { described_class.allowed?(user) }
+ .not_to change { user.last_credential_check_at }
end
end
describe '#allowed?' do
- subject { access.allowed? }
-
context 'when the user cannot be found' do
before do
- allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_dn).and_return(nil)
- allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_email).and_return(nil)
+ stub_ldap_person_find_by_dn(nil)
+ stub_ldap_person_find_by_email(user.email, nil)
end
- it { is_expected.to be_falsey }
+ it 'returns false' do
+ expect(access.allowed?).to be_falsey
+ end
it 'blocks user in GitLab' do
- expect(access).to receive(:block_user).with(user, 'does not exist anymore')
+ access.allowed?
+
+ expect(user).to be_blocked
+ expect(user).to be_ldap_blocked
+ end
+
+ it 'logs the reason' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ "LDAP account \"123456\" does not exist anymore, " \
+ "blocking Gitlab user \"#{user.name}\" (#{user.email})"
+ )
access.allowed?
end
end
context 'when the user is found' do
- let(:ldap_user) { Gitlab::Auth::LDAP::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
-
before do
- allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_dn).and_return(ldap_user)
+ stub_ldap_person_find_by_dn(Net::LDAP::Entry.new)
end
context 'and the user is disabled via active directory' do
@@ -55,10 +65,22 @@ describe Gitlab::Auth::LDAP::Access do
allow(Gitlab::Auth::LDAP::Person).to receive(:disabled_via_active_directory?).and_return(true)
end
- it { is_expected.to be_falsey }
+ it 'returns false' do
+ expect(access.allowed?).to be_falsey
+ end
it 'blocks user in GitLab' do
- expect(access).to receive(:block_user).with(user, 'is disabled in Active Directory')
+ access.allowed?
+
+ expect(user).to be_blocked
+ expect(user).to be_ldap_blocked
+ end
+
+ it 'logs the reason' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ "LDAP account \"123456\" is disabled in Active Directory, " \
+ "blocking Gitlab user \"#{user.name}\" (#{user.email})"
+ )
access.allowed?
end
@@ -92,7 +114,17 @@ describe Gitlab::Auth::LDAP::Access do
end
it 'unblocks user in GitLab' do
- expect(access).to receive(:unblock_user).with(user, 'is not disabled anymore')
+ access.allowed?
+
+ expect(user).not_to be_blocked
+ expect(user).not_to be_ldap_blocked
+ end
+
+ it 'logs the reason' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ "LDAP account \"123456\" is not disabled anymore, " \
+ "unblocking Gitlab user \"#{user.name}\" (#{user.email})"
+ )
access.allowed?
end
@@ -105,18 +137,32 @@ describe Gitlab::Auth::LDAP::Access do
allow_any_instance_of(Gitlab::Auth::LDAP::Config).to receive(:active_directory).and_return(false)
end
- it { is_expected.to be_truthy }
+ it 'returns true' do
+ expect(access.allowed?).to be_truthy
+ end
context 'when user cannot be found' do
before do
- allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_dn).and_return(nil)
- allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_email).and_return(nil)
+ stub_ldap_person_find_by_dn(nil)
+ stub_ldap_person_find_by_email(user.email, nil)
end
- it { is_expected.to be_falsey }
+ it 'returns false' do
+ expect(access.allowed?).to be_falsey
+ end
it 'blocks user in GitLab' do
- expect(access).to receive(:block_user).with(user, 'does not exist anymore')
+ access.allowed?
+
+ expect(user).to be_blocked
+ expect(user).to be_ldap_blocked
+ end
+
+ it 'logs the reason' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ "LDAP account \"123456\" does not exist anymore, " \
+ "blocking Gitlab user \"#{user.name}\" (#{user.email})"
+ )
access.allowed?
end
@@ -128,7 +174,17 @@ describe Gitlab::Auth::LDAP::Access do
end
it 'unblocks the user if it exists' do
- expect(access).to receive(:unblock_user).with(user, 'is available again')
+ access.allowed?
+
+ expect(user).not_to be_blocked
+ expect(user).not_to be_ldap_blocked
+ end
+
+ it 'logs the reason' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ "LDAP account \"123456\" is available again, " \
+ "unblocking Gitlab user \"#{user.name}\" (#{user.email})"
+ )
access.allowed?
end
@@ -152,46 +208,4 @@ describe Gitlab::Auth::LDAP::Access do
end
end
end
-
- describe '#block_user' do
- before do
- user.activate
- allow(Gitlab::AppLogger).to receive(:info)
-
- access.block_user user, 'reason'
- end
-
- it 'blocks the user' do
- expect(user).to be_blocked
- expect(user).to be_ldap_blocked
- end
-
- it 'logs the reason' do
- expect(Gitlab::AppLogger).to have_received(:info).with(
- "LDAP account \"123456\" reason, " \
- "blocking Gitlab user \"#{user.name}\" (#{user.email})"
- )
- end
- end
-
- describe '#unblock_user' do
- before do
- user.ldap_block
- allow(Gitlab::AppLogger).to receive(:info)
-
- access.unblock_user user, 'reason'
- end
-
- it 'activates the user' do
- expect(user).not_to be_blocked
- expect(user).not_to be_ldap_blocked
- end
-
- it 'logs the reason' do
- Gitlab::AppLogger.info(
- "LDAP account \"123456\" reason, " \
- "unblocking Gitlab user \"#{user.name}\" (#{user.email})"
- )
- end
- end
end
diff --git a/spec/lib/gitlab/auth/o_auth/provider_spec.rb b/spec/lib/gitlab/auth/o_auth/provider_spec.rb
index fc35d430917..80d702cf9dc 100644
--- a/spec/lib/gitlab/auth/o_auth/provider_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/provider_spec.rb
@@ -1,6 +1,48 @@
require 'spec_helper'
describe Gitlab::Auth::OAuth::Provider do
+ describe '.enabled?' do
+ before do
+ allow(described_class).to receive(:providers).and_return([:ldapmain, :google_oauth2])
+ end
+
+ context 'when OmniAuth is disabled' do
+ before do
+ allow(Gitlab::Auth).to receive(:omniauth_enabled?).and_return(false)
+ end
+
+ it 'allows database auth' do
+ expect(described_class.enabled?('database')).to be_truthy
+ end
+
+ it 'allows LDAP auth' do
+ expect(described_class.enabled?('ldapmain')).to be_truthy
+ end
+
+ it 'does not allow other OmniAuth providers' do
+ expect(described_class.enabled?('google_oauth2')).to be_falsey
+ end
+ end
+
+ context 'when OmniAuth is enabled' do
+ before do
+ allow(Gitlab::Auth).to receive(:omniauth_enabled?).and_return(true)
+ end
+
+ it 'allows database auth' do
+ expect(described_class.enabled?('database')).to be_truthy
+ end
+
+ it 'allows LDAP auth' do
+ expect(described_class.enabled?('ldapmain')).to be_truthy
+ end
+
+ it 'allows other OmniAuth providers' do
+ expect(described_class.enabled?('google_oauth2')).to be_truthy
+ end
+ end
+ end
+
describe '#config_for' do
context 'for an LDAP provider' do
context 'when the provider exists' do
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
index d53a7d468e3..8b92088902b 100644
--- a/spec/lib/gitlab/ci/status/build/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -88,7 +88,7 @@ describe Gitlab::Ci::Status::Build::Factory do
expect(status.icon).to eq 'status_failed'
expect(status.favicon).to eq 'favicon_status_failed'
expect(status.label).to eq 'failed'
- expect(status.status_tooltip).to eq 'failed <br> (unknown failure)'
+ expect(status.status_tooltip).to eq 'failed - (unknown failure)'
expect(status).to have_details
expect(status).to have_action
end
diff --git a/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
index bfaa508785e..af03d5a1308 100644
--- a/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
@@ -76,7 +76,7 @@ describe Gitlab::Ci::Status::Build::FailedAllowed do
let(:status) { described_class.new(build_status) }
it 'does override badge_tooltip' do
- expect(status.badge_tooltip).to eq('failed <br> (unknown failure)')
+ expect(status.badge_tooltip).to eq('failed - (unknown failure)')
end
end
@@ -87,7 +87,7 @@ describe Gitlab::Ci::Status::Build::FailedAllowed do
let(:status) { described_class.new(build_status) }
it 'does override status_tooltip' do
- expect(status.status_tooltip).to eq 'failed <br> (unknown failure) (allowed to fail)'
+ expect(status.status_tooltip).to eq 'failed - (unknown failure) (allowed to fail)'
end
end
diff --git a/spec/lib/gitlab/ci/status/build/failed_spec.rb b/spec/lib/gitlab/ci/status/build/failed_spec.rb
index b6676b40fd3..e424270f7c5 100644
--- a/spec/lib/gitlab/ci/status/build/failed_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/failed_spec.rb
@@ -52,7 +52,7 @@ describe Gitlab::Ci::Status::Build::Failed do
let(:status) { Gitlab::Ci::Status::Failed.new(build, user) }
it 'does override badge_tooltip' do
- expect(subject.badge_tooltip).to eq 'failed <br> (script failure)'
+ expect(subject.badge_tooltip).to eq 'failed - (script failure)'
end
end
@@ -61,7 +61,7 @@ describe Gitlab::Ci::Status::Build::Failed do
let(:status) { Gitlab::Ci::Status::Failed.new(build, user) }
it 'does override status_tooltip' do
- expect(subject.status_tooltip).to eq 'failed <br> (script failure)'
+ expect(subject.status_tooltip).to eq 'failed - (script failure)'
end
end
diff --git a/spec/lib/gitlab/ci/status/build/retried_spec.rb b/spec/lib/gitlab/ci/status/build/retried_spec.rb
index ee9acaf1c21..76c2fb01e3f 100644
--- a/spec/lib/gitlab/ci/status/build/retried_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/retried_spec.rb
@@ -66,7 +66,7 @@ describe Gitlab::Ci::Status::Build::Retried do
let(:status) { Gitlab::Ci::Status::Build::Failed.new(failed_status) }
it 'does override status_tooltip' do
- expect(subject.status_tooltip).to eq 'failed <br> (unknown failure) (retried)'
+ expect(subject.status_tooltip).to eq 'failed - (unknown failure) (retried)'
end
end
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 5b343920429..9095ffbfd52 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -69,10 +69,6 @@ describe Gitlab::Conflict::File do
CGI.unescapeHTML(ActionView::Base.full_sanitizer.sanitize(html)).delete("\n")
end
- it 'modifies the existing lines' do
- expect { conflict_file.highlight_lines! }.to change { conflict_file.lines.map(&:instance_variables) }
- end
-
it 'is called implicitly when rich_text is accessed on a line' do
expect(conflict_file).to receive(:highlight_lines!).once.and_call_original
diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb
index 7c9e8c8d04e..3c8cf9c56cc 100644
--- a/spec/lib/gitlab/diff/highlight_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_spec.rb
@@ -24,19 +24,19 @@ describe Gitlab::Diff::Highlight do
it 'highlights and marks unchanged lines' do
code = %Q{ <span id="LC7" class="line" lang="ruby"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>\n}
- expect(subject[2].text).to eq(code)
+ expect(subject[2].rich_text).to eq(code)
end
it 'highlights and marks removed lines' do
code = %Q{-<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>\n}
- expect(subject[4].text).to eq(code)
+ expect(subject[4].rich_text).to eq(code)
end
it 'highlights and marks added lines' do
code = %Q{+<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="no"><span class="idiff left">RuntimeError</span></span><span class="p"><span class="idiff">,</span></span><span class="idiff right"> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
- expect(subject[5].text).to eq(code)
+ expect(subject[5].rich_text).to eq(code)
end
end
@@ -69,8 +69,8 @@ describe Gitlab::Diff::Highlight do
it 'marks added lines' do
code = %q{+ raise <span class="idiff left right">RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;}
- expect(subject[5].text).to eq(code)
- expect(subject[5].text).to be_html_safe
+ expect(subject[5].rich_text).to eq(code)
+ expect(subject[5].rich_text).to be_html_safe
end
context 'when the inline diff marker has an invalid range' do
diff --git a/spec/lib/gitlab/diff/line_spec.rb b/spec/lib/gitlab/diff/line_spec.rb
new file mode 100644
index 00000000000..76d411973c7
--- /dev/null
+++ b/spec/lib/gitlab/diff/line_spec.rb
@@ -0,0 +1,22 @@
+describe Gitlab::Diff::Line do
+ describe '.init_from_hash' do
+ it 'round-trips correctly with to_hash' do
+ line = described_class.new('<input>', 'match', 0, 0, 1,
+ parent_file: double(:file),
+ line_code: double(:line_code),
+ rich_text: '&lt;input&gt;')
+
+ expect(described_class.init_from_hash(line.to_hash).to_hash)
+ .to eq(line.to_hash)
+ end
+ end
+
+ context "when setting rich text" do
+ it 'escapes any HTML special characters in the diff chunk header' do
+ subject = described_class.new("<input>", "", 0, 0, 0)
+ line = subject.as_json
+
+ expect(line[:rich_text]).to eq("&lt;input&gt;")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb
index 3f7a12144d5..65a2e1cb5cb 100644
--- a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb
@@ -92,7 +92,7 @@ describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cach
.with(issue)
.and_return([user.id, true])
- expect(Gitlab::GithubImport)
+ expect(importer)
.to receive(:insert_and_return_id)
.with(
{
@@ -121,7 +121,7 @@ describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cach
.with(issue)
.and_return([project.creator_id, false])
- expect(Gitlab::GithubImport)
+ expect(importer)
.to receive(:insert_and_return_id)
.with(
{
@@ -150,7 +150,7 @@ describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cach
.with(issue)
.and_return([user.id, true])
- expect(Gitlab::GithubImport)
+ expect(importer)
.to receive(:insert_and_return_id)
.and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key')
@@ -185,7 +185,7 @@ describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cach
.and_return([user.id, true])
issue = build_stubbed(:issue, project: project)
- allow(Gitlab::GithubImport)
+ allow(importer)
.to receive(:insert_and_return_id)
.and_return(issue.id)
allow(project.issues).to receive(:find).with(issue.id).and_return(issue)
diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
index 44c920043b4..25684ea9e2c 100644
--- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
@@ -80,7 +80,7 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi
end
it 'imports the pull request with the pull request author as the merge request author' do
- expect(Gitlab::GithubImport)
+ expect(importer)
.to receive(:insert_and_return_id)
.with(
{
@@ -114,7 +114,7 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi
it 'triggers internal_id functionality to track greatest iids' do
mr = build_stubbed(:merge_request, source_project: project, target_project: project)
- allow(Gitlab::GithubImport).to receive(:insert_and_return_id).and_return(mr.id)
+ allow(importer).to receive(:insert_and_return_id).and_return(mr.id)
allow(project.merge_requests).to receive(:find).with(mr.id).and_return(mr)
expect(mr).to receive(:ensure_target_project_iid!)
@@ -135,7 +135,7 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi
.with(pull_request)
.and_return(user.id)
- expect(Gitlab::GithubImport)
+ expect(importer)
.to receive(:insert_and_return_id)
.with(
{
@@ -181,7 +181,7 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi
.to receive(:source_branch)
.and_return('master')
- expect(Gitlab::GithubImport)
+ expect(importer)
.to receive(:insert_and_return_id)
.with(
{
@@ -219,7 +219,7 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi
.with(pull_request)
.and_return(user.id)
- expect(Gitlab::GithubImport)
+ expect(importer)
.to receive(:insert_and_return_id)
.and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key')
diff --git a/spec/lib/gitlab/github_import_spec.rb b/spec/lib/gitlab/github_import_spec.rb
index 51414800e8c..496244c91bf 100644
--- a/spec/lib/gitlab/github_import_spec.rb
+++ b/spec/lib/gitlab/github_import_spec.rb
@@ -27,39 +27,6 @@ describe Gitlab::GithubImport do
end
end
- describe '.insert_and_return_id' do
- let(:attributes) { { iid: 1, title: 'foo' } }
- let(:project) { create(:project) }
-
- context 'on PostgreSQL' do
- it 'returns the ID returned by the query' do
- expect(Gitlab::Database)
- .to receive(:bulk_insert)
- .with(Issue.table_name, [attributes], return_ids: true)
- .and_return([10])
-
- id = described_class.insert_and_return_id(attributes, project.issues)
-
- expect(id).to eq(10)
- end
- end
-
- context 'on MySQL' do
- it 'uses a separate query to retrieve the ID' do
- issue = create(:issue, project: project, iid: attributes[:iid])
-
- expect(Gitlab::Database)
- .to receive(:bulk_insert)
- .with(Issue.table_name, [attributes], return_ids: true)
- .and_return([])
-
- id = described_class.insert_and_return_id(attributes, project.issues)
-
- expect(id).to eq(issue.id)
- end
- end
- end
-
describe '.ghost_user_id', :clean_gitlab_redis_cache do
it 'returns the ID of the ghost user' do
expect(described_class.ghost_user_id).to eq(User.ghost.id)
diff --git a/spec/lib/gitlab/import/database_helpers_spec.rb b/spec/lib/gitlab/import/database_helpers_spec.rb
new file mode 100644
index 00000000000..e716155b7d5
--- /dev/null
+++ b/spec/lib/gitlab/import/database_helpers_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Import::DatabaseHelpers do
+ let(:database_helper) do
+ Class.new do
+ include Gitlab::Import::DatabaseHelpers
+ end
+ end
+
+ subject { database_helper.new }
+
+ describe '.insert_and_return_id' do
+ let(:attributes) { { iid: 1, title: 'foo' } }
+ let(:project) { create(:project) }
+
+ context 'on PostgreSQL' do
+ it 'returns the ID returned by the query' do
+ expect(Gitlab::Database)
+ .to receive(:bulk_insert)
+ .with(Issue.table_name, [attributes], return_ids: true)
+ .and_return([10])
+
+ id = subject.insert_and_return_id(attributes, project.issues)
+
+ expect(id).to eq(10)
+ end
+ end
+
+ context 'on MySQL' do
+ it 'uses a separate query to retrieve the ID' do
+ issue = create(:issue, project: project, iid: attributes[:iid])
+
+ expect(Gitlab::Database)
+ .to receive(:bulk_insert)
+ .with(Issue.table_name, [attributes], return_ids: true)
+ .and_return([])
+
+ id = subject.insert_and_return_id(attributes, project.issues)
+
+ expect(id).to eq(issue.id)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import/merge_request_creator_spec.rb b/spec/lib/gitlab/import/merge_request_creator_spec.rb
new file mode 100644
index 00000000000..7c73e9b39f7
--- /dev/null
+++ b/spec/lib/gitlab/import/merge_request_creator_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Import::MergeRequestCreator do
+ let(:project) { create(:project, :repository) }
+
+ subject { described_class.new(project) }
+
+ describe '#execute' do
+ context 'merge request already exists' do
+ let(:merge_request) { create(:merge_request, target_project: project, source_project: project) }
+ let(:commits) { merge_request.merge_request_diffs.first.commits }
+ let(:attributes) { HashWithIndifferentAccess.new(merge_request.attributes.except("merge_params")) }
+
+ it 'updates the data' do
+ commits_count = commits.count
+ merge_request.merge_request_diffs.destroy_all # rubocop: disable DestroyAll
+
+ expect(merge_request.merge_request_diffs.count).to eq(0)
+
+ subject.execute(attributes)
+
+ expect(merge_request.reload.merge_request_diffs.count).to eq(1)
+ expect(merge_request.reload.merge_request_diffs.first.commits.count).to eq(commits_count)
+ end
+ end
+
+ context 'new merge request' do
+ let(:merge_request) { build(:merge_request, target_project: project, source_project: project) }
+ let(:attributes) { HashWithIndifferentAccess.new(merge_request.attributes.except("merge_params")) }
+
+ it 'creates a new merge request' do
+ attributes.delete(:id)
+
+ expect { subject.execute(attributes) }.to change { MergeRequest.count }.by(1)
+
+ new_mr = MergeRequest.last
+ expect(new_mr.merge_request_diffs.count).to eq(1)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb
index 9c3870a0af8..f799de18cd0 100644
--- a/spec/lib/gitlab/import_export/uploads_manager_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb
@@ -36,6 +36,38 @@ describe Gitlab::ImportExport::UploadsManager do
expect(File).to exist(exported_file_path)
end
+
+ context 'with orphaned project upload files' do
+ let(:orphan_path) { File.join(FileUploader.absolute_base_dir(project), 'f93f088ddf492ffd950cf059002cbbb6', 'orphan.jpg') }
+ let(:exported_orphan_path) { "#{shared.export_path}/uploads/f93f088ddf492ffd950cf059002cbbb6/orphan.jpg" }
+
+ before do
+ FileUtils.mkdir_p(File.dirname(orphan_path))
+ FileUtils.touch(orphan_path)
+ end
+
+ after do
+ File.delete(orphan_path) if File.exist?(orphan_path)
+ end
+
+ it 'excludes orphaned upload files' do
+ manager.save
+
+ expect(File).not_to exist(exported_orphan_path)
+ end
+ end
+
+ context 'with an upload missing its file' do
+ before do
+ File.delete(upload.absolute_path)
+ end
+
+ it 'does not cause errors' do
+ manager.save
+
+ expect(shared.errors).to be_empty
+ end
+ end
end
context 'using object storage' do
diff --git a/spec/lib/gitlab/middleware/multipart_spec.rb b/spec/lib/gitlab/middleware/multipart_spec.rb
index f788f8ee276..daf454665b0 100644
--- a/spec/lib/gitlab/middleware/multipart_spec.rb
+++ b/spec/lib/gitlab/middleware/multipart_spec.rb
@@ -75,6 +75,26 @@ describe Gitlab::Middleware::Multipart do
it_behaves_like 'multipart upload files'
end
+ it 'allows files in uploads/tmp directory' do
+ Dir.mktmpdir do |dir|
+ uploads_dir = File.join(dir, 'public/uploads/tmp')
+ FileUtils.mkdir_p(uploads_dir)
+
+ allow(Rails).to receive(:root).and_return(dir)
+ allow(Dir).to receive(:tmpdir).and_return(File.join(Dir.tmpdir, 'tmpsubdir'))
+
+ Tempfile.open('top-level', uploads_dir) do |tempfile|
+ env = post_env({ 'file' => tempfile.path }, { 'file.name' => original_filename, 'file.path' => tempfile.path }, Gitlab::Workhorse.secret, 'gitlab-workhorse')
+
+ expect(app).to receive(:call) do |env|
+ expect(Rack::Request.new(env).params['file']).to be_a(::UploadedFile)
+ end
+
+ middleware.call(env)
+ end
+ end
+ end
+
it 'allows symlinks for uploads dir' do
Tempfile.open('two-levels') do |tempfile|
symlinked_dir = '/some/dir/uploads'
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index 6f5f9938eca..624e2add860 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -1,3 +1,4 @@
+# coding: utf-8
require 'spec_helper'
describe Gitlab::UrlBlocker do
@@ -82,6 +83,17 @@ describe Gitlab::UrlBlocker do
expect(described_class).not_to be_blocked_url("http://#{ip}")
end
end
+
+ it 'allows IPv4 link-local endpoints' do
+ expect(described_class).not_to be_blocked_url('http://169.254.169.254')
+ expect(described_class).not_to be_blocked_url('http://169.254.168.100')
+ end
+
+ # This is blocked due to the hostname check: https://gitlab.com/gitlab-org/gitlab-ce/issues/50227
+ it 'blocks IPv6 link-local endpoints' do
+ expect(described_class).to be_blocked_url('http://[::ffff:169.254.169.254]')
+ expect(described_class).to be_blocked_url('http://[::ffff:169.254.168.100]')
+ end
end
context 'false' do
@@ -96,10 +108,21 @@ describe Gitlab::UrlBlocker do
expect(described_class).to be_blocked_url("http://#{ip}", allow_local_network: false)
end
end
+
+ it 'blocks IPv4 link-local endpoints' do
+ expect(described_class).to be_blocked_url('http://169.254.169.254', allow_local_network: false)
+ expect(described_class).to be_blocked_url('http://169.254.168.100', allow_local_network: false)
+ end
+
+ it 'blocks IPv6 link-local endpoints' do
+ expect(described_class).to be_blocked_url('http://[::ffff:169.254.169.254]', allow_local_network: false)
+ expect(described_class).to be_blocked_url('http://[::ffff:169.254.168.100]', allow_local_network: false)
+ expect(described_class).to be_blocked_url('http://[FE80::C800:EFF:FE74:8]', allow_local_network: false)
+ end
end
def stub_domain_resolv(domain, ip)
- allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([double(ip_address: ip, ipv4_private?: true)])
+ allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([double(ip_address: ip, ipv4_private?: true, ipv6_link_local?: false)])
end
def unstub_domain_resolv
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index a19b3c0ba66..de6dd2a9fea 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -56,6 +56,7 @@ describe Gitlab::UsageData do
expect(count_data[:projects]).to eq(3)
expect(count_data.keys).to match_array(%i(
+ assignee_lists
boards
ci_builds
ci_internal_pipelines
@@ -83,9 +84,11 @@ describe Gitlab::UsageData do
groups
issues
keys
+ label_lists
labels
lfs_objects
merge_requests
+ milestone_lists
milestones
notes
projects
diff --git a/spec/migrations/drop_duplicate_protected_tags_spec.rb b/spec/migrations/drop_duplicate_protected_tags_spec.rb
new file mode 100644
index 00000000000..acfb6850722
--- /dev/null
+++ b/spec/migrations/drop_duplicate_protected_tags_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20180711103851_drop_duplicate_protected_tags.rb')
+
+describe DropDuplicateProtectedTags, :migration do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:protected_tags) { table(:protected_tags) }
+
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 2)
+
+ namespaces.create(id: 1, name: 'gitlab-org', path: 'gitlab-org')
+ projects.create!(id: 1, namespace_id: 1, name: 'gitlab1', path: 'gitlab1')
+ projects.create!(id: 2, namespace_id: 1, name: 'gitlab2', path: 'gitlab2')
+ end
+
+ it 'removes duplicated protected tags' do
+ protected_tags.create!(id: 1, project_id: 1, name: 'foo')
+ tag2 = protected_tags.create!(id: 2, project_id: 1, name: 'foo1')
+ protected_tags.create!(id: 3, project_id: 1, name: 'foo')
+ tag4 = protected_tags.create!(id: 4, project_id: 1, name: 'foo')
+ tag5 = protected_tags.create!(id: 5, project_id: 2, name: 'foo')
+
+ migrate!
+
+ expect(protected_tags.all.count).to eq 3
+ expect(protected_tags.all.pluck(:id)).to contain_exactly(tag2.id, tag4.id, tag5.id)
+ end
+
+ it 'does not remove unique protected tags' do
+ tag1 = protected_tags.create!(id: 1, project_id: 1, name: 'foo1')
+ tag2 = protected_tags.create!(id: 2, project_id: 1, name: 'foo2')
+ tag3 = protected_tags.create!(id: 3, project_id: 1, name: 'foo3')
+
+ migrate!
+
+ expect(protected_tags.all.count).to eq 3
+ expect(protected_tags.all.pluck(:id)).to contain_exactly(tag1.id, tag2.id, tag3.id)
+ end
+end
diff --git a/spec/models/concerns/awardable_spec.rb b/spec/models/concerns/awardable_spec.rb
index a980cff28fb..69083bdc125 100644
--- a/spec/models/concerns/awardable_spec.rb
+++ b/spec/models/concerns/awardable_spec.rb
@@ -53,21 +53,14 @@ describe Awardable do
issue.project.add_guest(user)
end
- it 'does not allow upvoting or downvoting your own issue' do
- issue.update!(author: user)
-
- expect(issue.user_can_award?(user, AwardEmoji::DOWNVOTE_NAME)).to be_falsy
- expect(issue.user_can_award?(user, AwardEmoji::UPVOTE_NAME)).to be_falsy
- end
-
it 'is truthy when the user is allowed to award emoji' do
- expect(issue.user_can_award?(user, AwardEmoji::UPVOTE_NAME)).to be_truthy
+ expect(issue.user_can_award?(user)).to be_truthy
end
it 'is falsy when the project is archived' do
issue.project.update!(archived: true)
- expect(issue.user_can_award?(user, AwardEmoji::UPVOTE_NAME)).to be_falsy
+ expect(issue.user_can_award?(user)).to be_falsy
end
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 84edfc3ff00..c21d85fb2a4 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -188,98 +188,6 @@ describe Issue do
end
end
- describe '#closed_by_merge_requests' do
- let(:project) { create(:project, :repository) }
- let(:issue) { create(:issue, project: project)}
- let(:closed_issue) { build(:issue, :closed, project: project)}
-
- let(:mr) do
- opts = {
- title: 'Awesome merge_request',
- description: "Fixes #{issue.to_reference}",
- source_branch: 'feature',
- target_branch: 'master'
- }
- MergeRequests::CreateService.new(project, project.owner, opts).execute
- end
-
- let(:closed_mr) do
- opts = {
- title: 'Awesome merge_request 2',
- description: "Fixes #{issue.to_reference}",
- source_branch: 'feature',
- target_branch: 'master',
- state: 'closed'
- }
- MergeRequests::CreateService.new(project, project.owner, opts).execute
- end
-
- it 'returns the merge request to close this issue' do
- expect(issue.closed_by_merge_requests(mr.author)).to eq([mr])
- end
-
- it "returns an empty array when the merge request is closed already" do
- expect(issue.closed_by_merge_requests(closed_mr.author)).to eq([])
- end
-
- it "returns an empty array when the current issue is closed already" do
- expect(closed_issue.closed_by_merge_requests(closed_issue.author)).to eq([])
- end
- end
-
- describe '#referenced_merge_requests' do
- let(:project) { create(:project, :public) }
- let(:issue) do
- create(:issue, description: merge_request.to_reference, project: project)
- end
- let!(:merge_request) do
- create(:merge_request,
- source_project: project,
- source_branch: 'master',
- target_branch: 'feature')
- end
-
- it 'returns the referenced merge requests' do
- mr2 = create(:merge_request,
- source_project: project,
- source_branch: 'feature',
- target_branch: 'master')
-
- create(:note_on_issue,
- noteable: issue,
- note: mr2.to_reference,
- project_id: project.id)
-
- expect(issue.referenced_merge_requests).to eq([merge_request, mr2])
- end
-
- it 'returns cross project referenced merge requests' do
- other_project = create(:project, :public)
- cross_project_merge_request = create(:merge_request, source_project: other_project)
- create(:note_on_issue,
- noteable: issue,
- note: cross_project_merge_request.to_reference(issue.project),
- project_id: issue.project.id)
-
- expect(issue.referenced_merge_requests).to eq([merge_request, cross_project_merge_request])
- end
-
- it 'excludes cross project references if the user cannot read cross project' do
- user = create(:user)
- allow(Ability).to receive(:allowed?).and_call_original
- expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
-
- other_project = create(:project, :public)
- cross_project_merge_request = create(:merge_request, source_project: other_project)
- create(:note_on_issue,
- noteable: issue,
- note: cross_project_merge_request.to_reference(issue.project),
- project_id: issue.project.id)
-
- expect(issue.referenced_merge_requests(user)).to eq([merge_request])
- end
- end
-
describe '#can_move?' do
let(:user) { create(:user) }
let(:issue) { create(:issue) }
@@ -365,7 +273,12 @@ describe Issue do
source_project: subject.project,
source_branch: "#{subject.iid}-branch" })
merge_request.create_cross_references!(user)
- expect(subject.referenced_merge_requests(user)).not_to be_empty
+
+ referenced_merge_requests = Issues::ReferencedMergeRequestsService
+ .new(subject.project, user)
+ .referenced_merge_requests(subject)
+
+ expect(referenced_merge_requests).not_to be_empty
expect(subject.related_branches(user)).to eq([subject.to_branch_name])
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 8cb706b54b0..7cfffbde42f 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2989,6 +2989,7 @@ describe Project do
# call. This makes testing a bit easier.
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
allow(project).to receive(:previous_changes).and_return('path' => ['foo'])
+ stub_feature_flags(skip_hashed_storage_upgrade: false)
end
it 'renames a repository' do
@@ -3160,6 +3161,7 @@ describe Project do
# call. This makes testing a bit easier.
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
allow(project).to receive(:previous_changes).and_return('path' => ['foo'])
+ stub_feature_flags(skip_hashed_storage_upgrade: false)
end
context 'migration to hashed storage' do
diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb
index c2ef0435c8e..269d5deca20 100644
--- a/spec/models/remote_mirror_spec.rb
+++ b/spec/models/remote_mirror_spec.rb
@@ -220,6 +220,18 @@ describe RemoteMirror do
end
end
+ context '#ensure_remote!' do
+ let(:remote_mirror) { create(:project, :repository, :remote_mirror).remote_mirrors.first }
+
+ it 'adds a remote multiple times with no errors' do
+ expect(remote_mirror.project.repository).to receive(:add_remote).with(remote_mirror.remote_name, remote_mirror.url).twice.and_call_original
+
+ 2.times do
+ remote_mirror.ensure_remote!
+ end
+ end
+ end
+
context '#updated_since?' do
let(:remote_mirror) { create(:project, :repository, :remote_mirror).remote_mirrors.first }
let(:timestamp) { Time.now - 5.minutes }
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 2859d5149ec..93898012d34 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -2005,6 +2005,24 @@ describe Repository do
File.delete(path)
end
+
+ context 'for multiple SHAs' do
+ it 'skips non-existent SHAs' do
+ repository.keep_around('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', sample_commit.id)
+
+ expect(repository.kept_around?(sample_commit.id)).to be_truthy
+ end
+
+ it 'skips already-kept-around SHAs' do
+ repository.keep_around(sample_commit.id)
+
+ expect(repository.raw_repository).to receive(:write_ref).exactly(1).and_call_original
+
+ repository.keep_around(sample_commit.id, another_sample_commit.id)
+
+ expect(repository.kept_around?(another_sample_commit.id)).to be_truthy
+ end
+ end
end
describe '#update_ref' do
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index 615fea11f26..5e583be457e 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -17,7 +17,7 @@ describe GroupPolicy do
let(:reporter_permissions) { [:admin_label] }
- let(:developer_permissions) { [:admin_milestones] }
+ let(:developer_permissions) { [:admin_milestone] }
let(:maintainer_permissions) do
[
@@ -31,6 +31,7 @@ describe GroupPolicy do
:admin_namespace,
:admin_group_member,
:change_visibility_level,
+ :set_note_created_at,
(Gitlab::Database.postgresql? ? :create_subgroup : nil)
].compact
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index dd3fa4e6a51..b7ec35d6ec5 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -64,6 +64,7 @@ describe ProjectPolicy do
%i[
change_namespace change_visibility_level rename_project remove_project
archive_project remove_fork_project destroy_merge_request destroy_issue
+ set_issue_iid set_issue_created_at set_note_created_at
]
end
diff --git a/spec/presenters/ci/build_presenter_spec.rb b/spec/presenters/ci/build_presenter_spec.rb
index 6dfaa3b72f7..547d95e0908 100644
--- a/spec/presenters/ci/build_presenter_spec.rb
+++ b/spec/presenters/ci/build_presenter_spec.rb
@@ -78,7 +78,7 @@ describe Ci::BuildPresenter do
it 'returns the reason of failure' do
status_title = presenter.status_title
- expect(status_title).to eq('Failed <br> (unknown failure)')
+ expect(status_title).to eq('Failed - (unknown failure)')
end
end
@@ -89,7 +89,7 @@ describe Ci::BuildPresenter do
status_title = presenter.status_title
expect(status_title).not_to include('(retried)')
- expect(status_title).to eq('Failed <br> (unknown failure)')
+ expect(status_title).to eq('Failed - (unknown failure)')
end
end
@@ -99,7 +99,7 @@ describe Ci::BuildPresenter do
it 'returns the reason of failure' do
status_title = presenter.status_title
- expect(status_title).to eq('Failed <br> (unknown failure)')
+ expect(status_title).to eq('Failed - (unknown failure)')
end
end
@@ -173,7 +173,7 @@ describe Ci::BuildPresenter do
it 'returns the reason of failure' do
tooltip = subject.tooltip_message
- expect(tooltip).to eq("#{build.name} - failed <br> (script failure)")
+ expect(tooltip).to eq("#{build.name} - failed - (script failure)")
end
end
@@ -183,7 +183,7 @@ describe Ci::BuildPresenter do
it 'should include the reason of failure and the retried title' do
tooltip = subject.tooltip_message
- expect(tooltip).to eq("#{build.name} - failed <br> (script failure) (retried)")
+ expect(tooltip).to eq("#{build.name} - failed - (script failure) (retried)")
end
end
@@ -193,7 +193,7 @@ describe Ci::BuildPresenter do
it 'should include the reason of failure' do
tooltip = subject.tooltip_message
- expect(tooltip).to eq("#{build.name} - failed <br> (script failure) (allowed to fail)")
+ expect(tooltip).to eq("#{build.name} - failed - (script failure) (allowed to fail)")
end
end
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index 0921fecb933..7f3f3ab0977 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -167,12 +167,6 @@ describe API::AwardEmoji do
expect(response).to have_gitlab_http_status(401)
end
- it "returns a 404 error if the user authored issue" do
- post api("/projects/#{project.id}/issues/#{issue2.id}/award_emoji", user), name: 'thumbsup'
-
- expect(response).to have_gitlab_http_status(404)
- end
-
it "normalizes +1 as thumbsup award" do
post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user), name: '+1'
@@ -215,12 +209,6 @@ describe API::AwardEmoji do
expect(json_response['user']['username']).to eq(user.username)
end
- it "it returns 404 error when user authored note" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note2.id}/award_emoji", user), name: 'thumbsup'
-
- expect(response).to have_gitlab_http_status(404)
- end
-
it "normalizes +1 as thumbsup award" do
post api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji", user), name: '+1'
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 28ba00c7293..f64815feffa 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -1023,6 +1023,20 @@ describe API::Issues do
end
end
+ context 'by a group owner' do
+ let(:group) { create(:group) }
+ let(:group_project) { create(:project, :public, namespace: group) }
+
+ it 'sets the internal ID on the new issue' do
+ group.add_owner(user2)
+ post api("/projects/#{group_project.id}/issues", user2),
+ title: 'new issue', iid: 9001
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['iid']).to eq 9001
+ end
+ end
+
context 'by another user' do
it 'ignores the given internal ID' do
post api("/projects/#{project.id}/issues", user2),
@@ -1154,14 +1168,47 @@ describe API::Issues do
end
end
- context 'when an admin or owner makes the request' do
- it 'accepts the creation date to be set' do
- creation_time = 2.weeks.ago
- post api("/projects/#{project.id}/issues", user),
- title: 'new issue', labels: 'label, label2', created_at: creation_time
+ context 'setting created_at' do
+ let(:creation_time) { 2.weeks.ago }
+ let(:params) { { title: 'new issue', labels: 'label, label2', created_at: creation_time } }
- expect(response).to have_gitlab_http_status(201)
- expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ context 'by an admin' do
+ it 'sets the creation time on the new issue' do
+ post api("/projects/#{project.id}/issues", admin), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'by a project owner' do
+ it 'sets the creation time on the new issue' do
+ post api("/projects/#{project.id}/issues", user), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'by a group owner' do
+ it 'sets the creation time on the new issue' do
+ group = create(:group)
+ group_project = create(:project, :public, namespace: group)
+ group.add_owner(user2)
+ post api("/projects/#{group_project.id}/issues", user2), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'by another user' do
+ it 'ignores the given creation time' do
+ post api("/projects/#{project.id}/issues", user2), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(Time.parse(json_response['created_at'])).not_to be_like_time(creation_time)
+ end
end
end
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index a4220f5b2be..b8a4a04a7e4 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -306,16 +306,16 @@ describe API::Labels do
end
it 'returns 400 for too long color code' do
- post api("/projects/#{project.id}/labels", user),
- name: 'Foo',
+ put api("/projects/#{project.id}/labels", user),
+ name: 'label1',
color: '#FFAAFFFF'
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['color']).to eq(['must be a valid color code'])
end
it 'returns 400 for invalid priority' do
- post api("/projects/#{project.id}/labels", user),
- name: 'Foo',
+ put api("/projects/#{project.id}/labels", user),
+ name: 'label1',
priority: 'foo'
expect(response).to have_gitlab_http_status(400)
diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb
index 6c05c166bd6..62613aa5938 100644
--- a/spec/requests/api/project_milestones_spec.rb
+++ b/spec/requests/api/project_milestones_spec.rb
@@ -39,19 +39,6 @@ describe API::ProjectMilestones do
expect(response).to have_gitlab_http_status(404)
end
-
- it "rejects a member with reporter access from deleting a milestone" do
- delete api("/projects/#{project.id}/milestones/#{milestone.id}", reporter)
-
- expect(response).to have_gitlab_http_status(403)
- end
-
- it 'deletes the milestone when the user has developer access to the project' do
- delete api("/projects/#{project.id}/milestones/#{milestone.id}", user)
-
- expect(project.milestones.find_by_id(milestone.id)).to be_nil
- expect(response).to have_gitlab_http_status(204)
- end
end
describe 'PUT /projects/:id/milestones/:milestone_id to test observer on close' do
diff --git a/spec/requests/api/protected_tags_spec.rb b/spec/requests/api/protected_tags_spec.rb
new file mode 100644
index 00000000000..f4f3ef31bc3
--- /dev/null
+++ b/spec/requests/api/protected_tags_spec.rb
@@ -0,0 +1,202 @@
+require 'spec_helper'
+
+describe API::ProtectedTags do
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, :repository) }
+ let(:project2) { create(:project, path: 'project2', namespace: user.namespace) }
+ let(:protected_name) { 'feature' }
+ let(:tag_name) { protected_name }
+ let!(:protected_tag) do
+ create(:protected_tag, project: project, name: protected_name)
+ end
+
+ describe 'GET /projects/:id/protected_tags' do
+ let(:route) { "/projects/#{project.id}/protected_tags" }
+
+ shared_examples_for 'protected tags' do
+ it 'returns the protected tags' do
+ get api(route, user), per_page: 100
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+
+ protected_tag_names = json_response.map { |x| x['name'] }
+ expected_tags_names = project.protected_tags.map { |x| x['name'] }
+ expect(protected_tag_names).to match_array(expected_tags_names)
+ end
+ end
+
+ context 'when authenticated as a maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it_behaves_like 'protected tags'
+ end
+
+ context 'when authenticated as a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it_behaves_like '403 response' do
+ let(:request) { get api(route, user) }
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/protected_tags/:tag' do
+ let(:route) { "/projects/#{project.id}/protected_tags/#{tag_name}" }
+
+ shared_examples_for 'protected tag' do
+ it 'returns the protected tag' do
+ get api(route, user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['name']).to eq(tag_name)
+ expect(json_response['create_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MAINTAINER)
+ end
+
+ context 'when protected tag does not exist' do
+ let(:tag_name) { 'unknown' }
+
+ it_behaves_like '404 response' do
+ let(:request) { get api(route, user) }
+ let(:message) { '404 Not found' }
+ end
+ end
+ end
+
+ context 'when authenticated as a maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it_behaves_like 'protected tag'
+
+ context 'when protected tag contains a wildcard' do
+ let(:protected_name) { 'feature*' }
+
+ it_behaves_like 'protected tag'
+ end
+ end
+
+ context 'when authenticated as a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it_behaves_like '403 response' do
+ let(:request) { get api(route, user) }
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/protected_tags' do
+ let(:tag_name) { 'new_tag' }
+
+ context 'when authenticated as a maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'protects a single tag with maintainers can create tags' do
+ post api("/projects/#{project.id}/protected_tags", user), name: tag_name
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['name']).to eq(tag_name)
+ expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
+ end
+
+ it 'protects a single tag with developers can create tags' do
+ post api("/projects/#{project.id}/protected_tags", user),
+ name: tag_name, create_access_level: 30
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['name']).to eq(tag_name)
+ expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER)
+ end
+
+ it 'protects a single tag with no one can create tags' do
+ post api("/projects/#{project.id}/protected_tags", user),
+ name: tag_name, create_access_level: 0
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['name']).to eq(tag_name)
+ expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS)
+ end
+
+ it 'returns a 422 error if the same tag is protected twice' do
+ post api("/projects/#{project.id}/protected_tags", user), name: protected_name
+
+ expect(response).to have_gitlab_http_status(422)
+ expect(json_response['message'][0]).to eq('Name has already been taken')
+ end
+
+ it 'returns 201 if the same tag is proteted on different projects' do
+ post api("/projects/#{project.id}/protected_tags", user), name: protected_name
+ post api("/projects/#{project2.id}/protected_tags", user), name: protected_name
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['name']).to eq(protected_name)
+ end
+
+ context 'when tag has a wildcard in its name' do
+ let(:tag_name) { 'feature/*' }
+
+ it 'protects multiple tags with a wildcard in the name' do
+ post api("/projects/#{project.id}/protected_tags", user), name: tag_name
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['name']).to eq(tag_name)
+ expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
+ end
+ end
+ end
+
+ context 'when authenticated as a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns a 403 error if guest' do
+ post api("/projects/#{project.id}/protected_tags/", user), name: tag_name
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/protected_tags/unprotect/:tag' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'unprotects a single tag' do
+ delete api("/projects/#{project.id}/protected_tags/#{tag_name}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) { api("/projects/#{project.id}/protected_tags/#{tag_name}", user) }
+ end
+
+ it "returns 404 if tag does not exist" do
+ delete api("/projects/#{project.id}/protected_tags/barfoo", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ context 'when tag has a wildcard in its name' do
+ let(:protected_name) { 'feature*' }
+
+ it 'unprotects a wildcard tag' do
+ delete api("/projects/#{project.id}/protected_tags/#{tag_name}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ end
+ end
+ end
+end
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index 98df5f787f7..77baaef7afd 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -103,11 +103,11 @@ describe Admin::HooksController, "routing" do
end
end
-# admin_hook_hook_log_retry GET /admin/hooks/:hook_id/hook_logs/:id/retry(.:format) admin/hook_logs#retry
+# admin_hook_hook_log_retry POST /admin/hooks/:hook_id/hook_logs/:id/retry(.:format) admin/hook_logs#retry
# admin_hook_hook_log GET /admin/hooks/:hook_id/hook_logs/:id(.:format) admin/hook_logs#show
describe Admin::HookLogsController, 'routing' do
it 'to #retry' do
- expect(get('/admin/hooks/1/hook_logs/1/retry')).to route_to('admin/hook_logs#retry', hook_id: '1', id: '1')
+ expect(post('/admin/hooks/1/hook_logs/1/retry')).to route_to('admin/hook_logs#retry', hook_id: '1', id: '1')
end
it 'to #show' do
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 70a7707826e..5abc6d81958 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -381,7 +381,7 @@ describe 'project routing' do
end
end
- # test_project_hook GET /:project_id/hooks/:id/test(.:format) hooks#test
+ # test_project_hook POST /:project_id/hooks/:id/test(.:format) hooks#test
# project_hooks GET /:project_id/hooks(.:format) hooks#index
# POST /:project_id/hooks(.:format) hooks#create
# edit_project_hook GET /:project_id/hooks/:id/edit(.:format) hooks#edit
@@ -398,11 +398,11 @@ describe 'project routing' do
end
end
- # retry_namespace_project_hook_hook_log GET /:project_id/hooks/:hook_id/hook_logs/:id/retry(.:format) projects/hook_logs#retry
+ # retry_namespace_project_hook_hook_log POST /:project_id/hooks/:hook_id/hook_logs/:id/retry(.:format) projects/hook_logs#retry
# namespace_project_hook_hook_log GET /:project_id/hooks/:hook_id/hook_logs/:id(.:format) projects/hook_logs#show
describe Projects::HookLogsController, 'routing' do
it 'to #retry' do
- expect(get('/gitlab/gitlabhq/hooks/1/hook_logs/1/retry')).to route_to('projects/hook_logs#retry', namespace_id: 'gitlab', project_id: 'gitlabhq', hook_id: '1', id: '1')
+ expect(post('/gitlab/gitlabhq/hooks/1/hook_logs/1/retry')).to route_to('projects/hook_logs#retry', namespace_id: 'gitlab', project_id: 'gitlabhq', hook_id: '1', id: '1')
end
it 'to #show' do
diff --git a/spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb b/spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb
new file mode 100644
index 00000000000..7bd50866577
--- /dev/null
+++ b/spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../rubocop/cop/ruby_interpolation_in_translation'
+
+# Disabling interpolation check as we deliberately want to have #{} in strings.
+# rubocop:disable Lint/InterpolationCheck
+describe RuboCop::Cop::RubyInterpolationInTranslation do
+ subject(:cop) { described_class.new }
+
+ it 'does not add an offence for a regular messages' do
+ inspect_source('_("Hello world")')
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it 'adds the correct offence when using interpolation in a string' do
+ inspect_source('_("Hello #{world}")')
+
+ offense = cop.offenses.first
+
+ expect(offense.location.source).to eq('#{world}')
+ expect(offense.message).to eq('Don\'t use ruby interpolation #{} inside translated strings, instead use %{}')
+ end
+
+ it 'detects when using a ruby interpolation in the first argument of a pluralized string' do
+ inspect_source('n_("Hello #{world}", "Hello world")')
+
+ expect(cop.offenses).not_to be_empty
+ end
+
+ it 'detects when using a ruby interpolation in the second argument of a pluralized string' do
+ inspect_source('n_("Hello world", "Hello #{world}")')
+
+ expect(cop.offenses).not_to be_empty
+ end
+
+ it 'detects when using interpolation in a namespaced translation' do
+ inspect_source('s_("Hello|#{world}")')
+
+ expect(cop.offenses).not_to be_empty
+ end
+
+ it 'does not add an offence for messages defined over multiple lines' do
+ source = <<~SRC
+ _("Hello "\
+ "world ")
+ SRC
+
+ inspect_source(source)
+ expect(cop.offenses).to be_empty
+ end
+
+ it 'adds an offence for violations in a message defined over multiple lines' do
+ source = <<~SRC
+ _("Hello "\
+ "\#{world} ")
+ SRC
+
+ inspect_source(source)
+ expect(cop.offenses).not_to be_empty
+ end
+end
+# rubocop:enable Lint/InterpolationCheck
diff --git a/spec/serializers/build_serializer_spec.rb b/spec/serializers/build_serializer_spec.rb
index 52459cd369d..302ef147eb2 100644
--- a/spec/serializers/build_serializer_spec.rb
+++ b/spec/serializers/build_serializer_spec.rb
@@ -37,7 +37,7 @@ describe BuildSerializer do
it 'serializes only status' do
expect(subject[:text]).to eq(status.text)
expect(subject[:label]).to eq('failed')
- expect(subject[:tooltip]).to eq('failed <br> (unknown failure)')
+ expect(subject[:tooltip]).to eq('failed - (unknown failure)')
expect(subject[:icon]).to eq(status.icon)
expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.png")
end
diff --git a/spec/serializers/job_entity_spec.rb b/spec/serializers/job_entity_spec.rb
index a5581a34517..8e1ca3f308d 100644
--- a/spec/serializers/job_entity_spec.rb
+++ b/spec/serializers/job_entity_spec.rb
@@ -142,7 +142,7 @@ describe JobEntity do
end
it 'should indicate the failure reason on tooltip' do
- expect(subject[:status][:tooltip]).to eq('failed <br> (API failure)')
+ expect(subject[:status][:tooltip]).to eq('failed - (API failure)')
end
it 'should include a callout message with a verbose output' do
@@ -166,7 +166,7 @@ describe JobEntity do
end
it 'should indicate the failure reason on tooltip' do
- expect(subject[:status][:tooltip]).to eq('failed <br> (API failure) (allowed to fail)')
+ expect(subject[:status][:tooltip]).to eq('failed - (API failure) (allowed to fail)')
end
it 'should include a callout message with a verbose output' do
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 3b1a302e217..d4528256640 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -204,16 +204,37 @@ describe GitPushService, services: true do
end
describe "Push Event" do
- let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) }
- let(:event) { Event.find_by_action(Event::PUSHED) }
+ context "with an existing branch" do
+ let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) }
+ let(:event) { Event.find_by_action(Event::PUSHED) }
- it { expect(event).to be_an_instance_of(PushEvent) }
- it { expect(event.project).to eq(project) }
- it { expect(event.action).to eq(Event::PUSHED) }
- it { expect(event.push_event_payload).to be_an_instance_of(PushEventPayload) }
- it { expect(event.push_event_payload.commit_from).to eq(oldrev) }
- it { expect(event.push_event_payload.commit_to).to eq(newrev) }
- it { expect(event.push_event_payload.ref).to eq('master') }
+ it 'generates a push event with one commit' do
+ expect(event).to be_an_instance_of(PushEvent)
+ expect(event.project).to eq(project)
+ expect(event.action).to eq(Event::PUSHED)
+ expect(event.push_event_payload).to be_an_instance_of(PushEventPayload)
+ expect(event.push_event_payload.commit_from).to eq(oldrev)
+ expect(event.push_event_payload.commit_to).to eq(newrev)
+ expect(event.push_event_payload.ref).to eq('master')
+ expect(event.push_event_payload.commit_count).to eq(1)
+ end
+ end
+
+ context "with a new branch" do
+ let!(:new_branch_data) { push_data_from_service(project, user, Gitlab::Git::BLANK_SHA, newrev, ref) }
+ let(:event) { Event.find_by_action(Event::PUSHED) }
+
+ it 'generates a push event with more than one commit' do
+ expect(event).to be_an_instance_of(PushEvent)
+ expect(event.project).to eq(project)
+ expect(event.action).to eq(Event::PUSHED)
+ expect(event.push_event_payload).to be_an_instance_of(PushEventPayload)
+ expect(event.push_event_payload.commit_from).to be_nil
+ expect(event.push_event_payload.commit_to).to eq(newrev)
+ expect(event.push_event_payload.ref).to eq('master')
+ expect(event.push_event_payload.commit_count).to be > 1
+ end
+ end
context "Updates merge requests" do
it "when pushing a new branch for the first time" do
@@ -224,6 +245,7 @@ describe GitPushService, services: true do
end
describe 'system hooks' do
+ let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) }
let(:system_hooks_service) { SystemHooksService.new }
it "sends a system hook after pushing a branch" do
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index d80d0f5a8a8..97a88b5d697 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -35,6 +35,14 @@ describe Groups::DestroyService do
it { expect(NotificationSetting.unscoped.all).not_to include(notification_setting) }
end
+ context 'site statistics' do
+ it 'doesnt trigger project deletion hooks twice' do
+ expect_any_instance_of(Project).to receive(:untrack_site_statistics).once
+
+ destroy_group(group, user, async)
+ end
+ end
+
context 'mattermost team' do
let!(:chat_team) { create(:chat_team, namespace: group) }
diff --git a/spec/services/issues/fetch_referenced_merge_requests_service_spec.rb b/spec/services/issues/fetch_referenced_merge_requests_service_spec.rb
deleted file mode 100644
index 4e58179f45f..00000000000
--- a/spec/services/issues/fetch_referenced_merge_requests_service_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'spec_helper.rb'
-
-describe Issues::FetchReferencedMergeRequestsService do
- let(:project) { create(:project) }
- let(:issue) { create(:issue, project: project) }
- let(:other_project) { create(:project) }
-
- let(:mr) { create(:merge_request, source_project: project, target_project: project, id: 2)}
- let(:other_mr) { create(:merge_request, source_project: other_project, target_project: other_project, id: 1)}
-
- let(:user) { create(:user) }
- let(:service) { described_class.new(project, user) }
-
- context 'with mentioned merge requests' do
- it 'returns a list of sorted merge requests' do
- allow(issue).to receive(:referenced_merge_requests).with(user).and_return([other_mr, mr])
-
- mrs, closed_by_mrs = service.execute(issue)
-
- expect(mrs).to match_array([mr, other_mr])
- expect(closed_by_mrs).to match_array([])
- end
- end
-
- context 'with closed-by merge requests' do
- it 'returns a list of sorted merge requests' do
- allow(issue).to receive(:closed_by_merge_requests).with(user).and_return([other_mr, mr])
-
- mrs, closed_by_mrs = service.execute(issue)
-
- expect(mrs).to match_array([])
- expect(closed_by_mrs).to match_array([mr, other_mr])
- end
- end
-end
diff --git a/spec/services/issues/referenced_merge_requests_service_spec.rb b/spec/services/issues/referenced_merge_requests_service_spec.rb
new file mode 100644
index 00000000000..61d1612829f
--- /dev/null
+++ b/spec/services/issues/referenced_merge_requests_service_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper.rb'
+
+describe Issues::ReferencedMergeRequestsService do
+ def create_referencing_mr(attributes = {})
+ create(:merge_request, attributes).tap do |merge_request|
+ create(:note, :system, project: project, noteable: issue, author: user, note: merge_request.to_reference(full: true))
+ end
+ end
+
+ def create_closing_mr(attributes = {})
+ create_referencing_mr(attributes).tap do |merge_request|
+ create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request)
+ end
+ end
+
+ set(:user) { create(:user) }
+ set(:project) { create(:project, :public, :repository) }
+ set(:other_project) { create(:project, :public, :repository) }
+ set(:issue) { create(:issue, author: user, project: project) }
+
+ set(:closing_mr) { create_closing_mr(source_project: project) }
+ set(:closing_mr_other_project) { create_closing_mr(source_project: other_project) }
+
+ set(:referencing_mr) { create_referencing_mr(source_project: project, source_branch: 'csv') }
+ set(:referencing_mr_other_project) { create_referencing_mr(source_project: other_project, source_branch: 'csv') }
+
+ let(:service) { described_class.new(project, user) }
+
+ describe '#execute' do
+ it 'returns a list of sorted merge requests' do
+ mrs, closed_by_mrs = service.execute(issue)
+
+ expect(mrs).to eq([closing_mr, referencing_mr, closing_mr_other_project, referencing_mr_other_project])
+ expect(closed_by_mrs).to eq([closing_mr, closing_mr_other_project])
+ end
+
+ context 'performance' do
+ it 'does not run extra queries when extra namespaces are included', :use_clean_rails_memory_store_caching do
+ service.execute(issue) # warm cache
+ control_count = ActiveRecord::QueryRecorder.new { service.execute(issue) }.count
+
+ third_project = create(:project, :public)
+ create_closing_mr(source_project: third_project)
+ service.execute(issue) # warm cache
+
+ expect { service.execute(issue) }.not_to exceed_query_limit(control_count)
+ end
+
+ it 'preloads the head pipeline for each merge request, and its routes' do
+ # Hack to ensure no data is preserved on issue before starting the spec,
+ # to avoid false negatives
+ reloaded_issue = Issue.find(issue.id)
+
+ pipeline_routes = lambda do |merge_requests|
+ merge_requests.map { |mr| mr.head_pipeline&.project&.full_path }
+ end
+
+ closing_mr_other_project.update!(head_pipeline: create(:ci_pipeline))
+ control_count = ActiveRecord::QueryRecorder.new { service.execute(reloaded_issue).each(&pipeline_routes) }
+
+ closing_mr.update!(head_pipeline: create(:ci_pipeline))
+
+ expect { service.execute(issue).each(&pipeline_routes) }
+ .not_to exceed_query_limit(control_count)
+ end
+
+ it 'only loads issue notes once' do
+ expect(issue).to receive(:notes).once.and_call_original
+
+ service.execute(issue)
+ end
+ end
+ end
+
+ describe '#referenced_merge_requests' do
+ it 'returns the referenced merge requests' do
+ expect(service.referenced_merge_requests(issue)).to match_array([
+ closing_mr,
+ closing_mr_other_project,
+ referencing_mr,
+ referencing_mr_other_project
+ ])
+ end
+
+ it 'excludes cross project references if the user cannot read cross project' do
+ allow(Ability).to receive(:allowed?).and_call_original
+ expect(Ability).to receive(:allowed?).with(user, :read_cross_project).at_least(:once).and_return(false)
+
+ expect(service.referenced_merge_requests(issue)).not_to include(closing_mr_other_project)
+ expect(service.referenced_merge_requests(issue)).not_to include(referencing_mr_other_project)
+ end
+
+ context 'performance' do
+ it 'does not run a query for each note author', :use_clean_rails_memory_store_caching do
+ service.referenced_merge_requests(issue) # warm cache
+ control_count = ActiveRecord::QueryRecorder.new { service.referenced_merge_requests(issue) }.count
+
+ create(:note, project: project, noteable: issue, author: create(:user))
+ service.referenced_merge_requests(issue) # warm cache
+
+ expect { service.referenced_merge_requests(issue) }.not_to exceed_query_limit(control_count)
+ end
+ end
+ end
+
+ describe '#closed_by_merge_requests' do
+ let(:closed_issue) { build(:issue, :closed, project: project)}
+
+ it 'returns the open merge requests that close this issue' do
+ create_closing_mr(source_project: project, state: 'closed')
+
+ expect(service.closed_by_merge_requests(issue)).to match_array([closing_mr, closing_mr_other_project])
+ end
+
+ it 'returns an empty array when the current issue is closed already' do
+ expect(service.closed_by_merge_requests(closed_issue)).to eq([])
+ end
+
+ context 'performance' do
+ it 'does not run a query for each note author', :use_clean_rails_memory_store_caching do
+ service.closed_by_merge_requests(issue) # warm cache
+ control_count = ActiveRecord::QueryRecorder.new { service.closed_by_merge_requests(issue) }.count
+
+ create(:note, :system, project: project, noteable: issue, author: create(:user))
+ service.closed_by_merge_requests(issue) # warm cache
+
+ expect { service.closed_by_merge_requests(issue) }.not_to exceed_query_limit(control_count)
+ end
+ end
+ end
+end
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 6aed481939e..0ced5d1b6d6 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -169,6 +169,10 @@ describe MergeRequests::BuildService do
end
end
+ it 'uses the title of the commit as the title of the merge request' do
+ expect(merge_request.title).to eq('Initial commit')
+ end
+
it 'appends the closing description' do
expected_description = [commit_description, closing_message].compact.join("\n\n")
diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb
index 6f3612501f4..8680e428517 100644
--- a/spec/services/milestones/destroy_service_spec.rb
+++ b/spec/services/milestones/destroy_service_spec.rb
@@ -4,8 +4,6 @@ describe Milestones::DestroyService do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) }
- let!(:issue) { create(:issue, project: project, milestone: milestone) }
- let!(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) }
before do
project.add_maintainer(user)
@@ -23,12 +21,23 @@ describe Milestones::DestroyService do
end
it 'deletes milestone id from issuables' do
+ issue = create(:issue, project: project, milestone: milestone)
+ merge_request = create(:merge_request, source_project: project, milestone: milestone)
+
service.execute(milestone)
expect(issue.reload.milestone).to be_nil
expect(merge_request.reload.milestone).to be_nil
end
+ it 'logs destroy event' do
+ service.execute(milestone)
+
+ event = Event.where(project_id: milestone.project_id, target_type: 'Milestone')
+
+ expect(event.count).to eq(1)
+ end
+
context 'group milestones' do
let(:group) { create(:group) }
let(:group_milestone) { create(:milestone, group: group) }
@@ -38,13 +47,20 @@ describe Milestones::DestroyService do
group.add_developer(user)
end
- it { expect(service.execute(group_milestone)).to be_nil }
+ it { expect(service.execute(group_milestone)).to eq(group_milestone) }
- it 'does not update milestone issuables' do
- expect(MergeRequests::UpdateService).not_to receive(:new)
- expect(Issues::UpdateService).not_to receive(:new)
+ it 'deletes milestone id from issuables' do
+ issue = create(:issue, project: project, milestone: group_milestone)
+ merge_request = create(:merge_request, source_project: project, milestone: group_milestone)
service.execute(group_milestone)
+
+ expect(issue.reload.milestone).to be_nil
+ expect(merge_request.reload.milestone).to be_nil
+ end
+
+ it 'does not log destroy event' do
+ expect { service.execute(group_milestone) }.not_to change { Event.count }
end
end
end
diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb
index 5c2e79ff9af..96e8a80b334 100644
--- a/spec/services/projects/update_remote_mirror_service_spec.rb
+++ b/spec/services/projects/update_remote_mirror_service_spec.rb
@@ -18,6 +18,7 @@ describe Projects::UpdateRemoteMirrorService do
end
it "fetches the remote repository" do
+ expect(remote_mirror).to receive(:ensure_remote!).and_call_original
expect(repository).to receive(:fetch_remote).with(remote_mirror.remote_name, no_tags: true) do
sync_remote(repository, remote_mirror.remote_name, local_branch_names)
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 9572b4110d5..695b9980548 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -249,9 +249,20 @@ describe Projects::UpdateService do
expect(project.errors.messages[:base]).to include('There is already a repository with that name on disk')
end
- context 'when hashed storage enabled' do
+ it 'renames the project without upgrading it' do
+ result = update_project(project, admin, path: 'new-path')
+
+ expect(result).not_to include(status: :error)
+ expect(project).to be_valid
+ expect(project.errors).to be_empty
+ expect(project.disk_path).to include('new-path')
+ expect(project.reload.hashed_storage?(:repository)).to be_falsey
+ end
+
+ context 'when hashed storage is enabled' do
before do
stub_application_setting(hashed_storage_enabled: true)
+ stub_feature_flags(skip_hashed_storage_upgrade: false)
end
it 'migrates project to a hashed storage instead of renaming the repo to another legacy name' do
@@ -262,6 +273,22 @@ describe Projects::UpdateService do
expect(project.errors).to be_empty
expect(project.reload.hashed_storage?(:repository)).to be_truthy
end
+
+ context 'when skip_hashed_storage_upgrade feature flag is enabled' do
+ before do
+ stub_feature_flags(skip_hashed_storage_upgrade: true)
+ end
+
+ it 'renames the project without upgrading it' do
+ result = update_project(project, admin, path: 'new-path')
+
+ expect(result).not_to include(status: :error)
+ expect(project).to be_valid
+ expect(project.errors).to be_empty
+ expect(project.disk_path).to include('new-path')
+ expect(project.reload.hashed_storage?(:repository)).to be_falsey
+ end
+ end
end
end
diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb
index afd6448aa26..3bebb7aae90 100644
--- a/spec/support/api/milestones_shared_examples.rb
+++ b/spec/support/api/milestones_shared_examples.rb
@@ -196,6 +196,24 @@ shared_examples_for 'group and project milestones' do |route_definition|
end
end
+ describe "DELETE #{route_definition}/:milestone_id" do
+ it "rejects a member with reporter access from deleting a milestone" do
+ reporter = create(:user)
+ milestone.parent.add_reporter(reporter)
+
+ delete api(resource_route, reporter)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+
+ it 'deletes the milestone when the user has developer access to the project' do
+ delete api(resource_route, user)
+
+ expect(project.milestones.find_by_id(milestone.id)).to be_nil
+ expect(response).to have_gitlab_http_status(204)
+ end
+ end
+
describe "GET #{route_definition}/:milestone_id/issues" do
let(:issues_route) { "#{route}/#{milestone.id}/issues" }
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index c228bd2393b..e0fceae88de 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -65,7 +65,9 @@ module CycleAnalyticsHelpers
end
def merge_merge_requests_closing_issue(user, project, issue)
- merge_requests = issue.closed_by_merge_requests(user)
+ merge_requests = Issues::ReferencedMergeRequestsService
+ .new(project, user)
+ .closed_by_merge_requests(issue)
merge_requests.each { |merge_request| MergeRequests::MergeService.new(project, user).execute(merge_request) }
end
diff --git a/spec/support/helpers/ldap_helpers.rb b/spec/support/helpers/ldap_helpers.rb
index b90bbc4b106..66ca5d7f0a3 100644
--- a/spec/support/helpers/ldap_helpers.rb
+++ b/spec/support/helpers/ldap_helpers.rb
@@ -37,6 +37,23 @@ module LdapHelpers
.to receive(:find_by_uid).with(uid, any_args).and_return(return_value)
end
+ def stub_ldap_person_find_by_dn(entry, provider = 'ldapmain')
+ person = ::Gitlab::Auth::LDAP::Person.new(entry, provider) if entry.present?
+
+ allow(::Gitlab::Auth::LDAP::Person)
+ .to receive(:find_by_dn)
+ .and_return(person)
+ end
+
+ def stub_ldap_person_find_by_email(email, entry, provider = 'ldapmain')
+ person = ::Gitlab::Auth::LDAP::Person.new(entry, provider) if entry.present?
+
+ allow(::Gitlab::Auth::LDAP::Person)
+ .to receive(:find_by_email)
+ .with(email, anything)
+ .and_return(person)
+ end
+
# Create a simple LDAP user entry.
def ldap_user_entry(uid)
entry = Net::LDAP::Entry.new
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index 1823099dd9c..8475f91799b 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -68,6 +68,10 @@ module StubConfiguration
allow(Gitlab.config.repositories).to receive(:storages).and_return(Settingslogic.new(messages))
end
+ def stub_kerberos_setting(messages)
+ allow(Gitlab.config.kerberos).to receive_messages(to_settings(messages))
+ end
+
private
# Modifies stubbed messages to also stub possible predicate versions
diff --git a/spec/support/helpers/stub_feature_flags.rb b/spec/support/helpers/stub_feature_flags.rb
index b96338bf548..c54a871b157 100644
--- a/spec/support/helpers/stub_feature_flags.rb
+++ b/spec/support/helpers/stub_feature_flags.rb
@@ -1,4 +1,7 @@
module StubFeatureFlags
+ # Stub Feature flags with `flag_name: true/false`
+ #
+ # @param [Hash] features where key is feature name and value is boolean whether enabled or not
def stub_feature_flags(features)
features.each do |feature_name, enabled|
allow(Feature).to receive(:enabled?).with(feature_name) { enabled }
diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb
index 1b563021244..0e20dfe0725 100644
--- a/spec/support/shared_examples/requests/api/notes.rb
+++ b/spec/support/shared_examples/requests/api/notes.rb
@@ -111,17 +111,79 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
end
- context 'when an admin or owner makes the request' do
- it 'accepts the creation date to be set' do
- creation_time = 2.weeks.ago
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user),
- body: 'hi!', created_at: creation_time
+ context 'setting created_at' do
+ let(:creation_time) { 2.weeks.ago }
+ let(:params) { { body: 'hi!', created_at: creation_time } }
+
+ context 'by an admin' do
+ it 'sets the creation time on the new note' do
+ admin = create(:admin)
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", admin), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(admin.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time)
+ end
+ end
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
- expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time)
+ if parent_type == 'projects'
+ context 'by a project owner' do
+ it 'sets the creation time on the new note' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'by a group owner' do
+ it 'sets the creation time on the new note' do
+ user2 = create(:user)
+ group = create(:group)
+ group.add_owner(user2)
+ parent.update!(namespace: group)
+ user2.refresh_authorized_projects
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user2.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time)
+ end
+ end
+ elsif parent_type == 'groups'
+ context 'by a group owner' do
+ it 'sets the creation time on the new note' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time)
+ end
+ end
+ end
+
+ context 'by another user' do
+ it 'ignores the given creation time' do
+ user2 = create(:user)
+ parent.add_developer(user2)
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user2.username)
+ expect(Time.parse(json_response['created_at'])).not_to be_like_time(creation_time)
+ expect(Time.parse(json_response['updated_at'])).not_to be_like_time(creation_time)
+ end
end
end
diff --git a/spec/views/projects/merge_requests/_commits.html.haml_spec.rb b/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
index b1c6565c08a..a7628548de6 100644
--- a/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
@@ -20,6 +20,7 @@ describe 'projects/merge_requests/_commits.html.haml' do
assign(:merge_request, merge_request)
assign(:commits, merge_request.commits)
+ assign(:hidden_commit_count, 0)
end
it 'shows commits from source project' do
@@ -30,4 +31,16 @@ describe 'projects/merge_requests/_commits.html.haml' do
expect(rendered).to have_link(href: href)
end
+
+ context 'when there are hidden commits' do
+ before do
+ assign(:hidden_commit_count, 1)
+ end
+
+ it 'shows notice about omitted commits' do
+ render
+
+ expect(rendered).to match(/1 additional commit has been omitted to prevent performance issues/)
+ end
+ end
end
diff --git a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
index 9ab105c3238..8befae39d3a 100644
--- a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
@@ -9,6 +9,8 @@ describe 'projects/merge_requests/creations/_new_submit.html.haml' do
assign(:merge_request, merge_request)
assign(:commits, merge_request.commits)
+ assign(:hidden_commit_count, 0)
+ assign(:total_commit_count, merge_request.commits.count)
assign(:project, merge_request.target_project)
allow(view).to receive(:can?).and_return(true)
@@ -29,4 +31,17 @@ describe 'projects/merge_requests/creations/_new_submit.html.haml' do
expect(rendered).not_to have_text('Builds')
end
end
+
+ context 'when there are hidden commits' do
+ before do
+ assign(:pipelines, Ci::Pipeline.none)
+ assign(:hidden_commit_count, 2)
+ end
+
+ it 'shows notice about omitted commits' do
+ render
+
+ expect(rendered).to match(/2 additional commits have been omitted to prevent performance issues/)
+ end
+ end
end